0

我只是出于测试目的编写以下代码:

NSString *aStr = [[NSString alloc] initWithFormat:@"Foo"];
aStr = [aStr initWithFormat:@"Bar"];//Crashed here

我收到以下错误:

*** initialization method -initWithFormat:locale:arguments: cannot be sent to an abstract object of class __NSCFString: Create a concrete instance!

如果我写下面的代码同样的事情发生

NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:@"Foo"];
aStr = [aStr initWithFormat:@"Bar"]; //Crashed here

通过谷歌我知道这initWithFormat将返回NSCFString对象。我的问题是,如果NSCFString是派生类,NSString那么为什么我不能initWithFormatNSCFString. 如果可以停止可见性,我如何在代码中实现而不覆盖NSCFString(派生类)中的方法。

简而言之,如果 NSCFString 是 NSString 的派生类,那么为什么我不能在其上调用基类 (initWithFormat) 方法?

4

3 回答 3

1

我相信发生的事情是该[NSString initWithFormat:]方法注意到您没有提供任何格式说明符,因此没有NSString需要构建的对象,因此它只是返回NSString您传入的常量对象(@"Foo"):

NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:@"Foo"];

现在aStr的类型也是如此NSCFString。这是崩溃的原因:

aStr = [aStr initWithFormat:@"Bar"]; //Crashed here

但是,您永远不应该init在现有对象上调用方法,因此要纠正崩溃,请使用:

aStr = [[NSString alloc] initWithFormat:@"Bar"];

并像您一样使用格式说明符:

aStr = @"Foo";
aStr = @"Boo";

这是同一件事,只是更清晰,使用更少的代码并具有更好的性能。

于 2014-10-28T11:08:40.807 回答
0

你在问“为什么”。除了您忽略的答案“在同一个对象上调用 init 两次是 baaaad”之外,NSString 是一个类集群。

[NSString alloc] 返回一个不能真正用作字符串但需要调用 init 方法的通用对象。让我们考虑一些显而易见的事情: NSString 对象是不可变的,但是 [NSString alloc] 的结果不可能是不可变的,否则就不可能存储一个值,对吧?

该 init 方法实际上将返回一个不再接受 init 方法的不同对象。虽然 [NSString alloc] 是一个非常灵活的对象,它可以做任何事情,但在调用 init 方法后,您会得到一个对象,其中包含一个永远不能再次修改的字符串。

(Apple 的实现方式可能与我所说的不同,或者可能会改变他们的实现方式。不过,他们可以并且会做一些事情来阻止你做一些愚蠢的事情)。

还有一个警告:不要考虑继承 NSString。我可以保证你不会得到任何有用的东西。

于 2014-10-28T11:23:31.227 回答
0

根据文档,它返回一个NSString通过使用给定格式字符串作为模板初始化的对象,剩余的参数值将被替换到该模板中。

而且您还需要像下面这样使用:-

NSString *aStr = [[NSString alloc] initWithFormat:@"%@,%@",@"Foo",@"Bar"];
NSLog(@"%@",aStr);
于 2014-10-28T10:54:54.440 回答