我只是为了测试目的而编写以下代码:
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
的派生类,那么为什么我不能在NSCFString
上调用initWithFormat
方法。如果可以停止可见性,我如何在代码中实现而不重写NSCFString
(派生类)中的方法。
简单地说,如果NSCFString是NSString的派生类,那么为什么我不能调用它的基类(initWithFormat)方法呢?
我相信[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";
这是一样的,只是更清晰,使用更少的代码,具有更好的性能。
根据文档,它返回一个NSString
对象,该对象是通过使用给定的格式字符串作为模板初始化的,其余参数值将被替换到该模板中。
而且你还需要像下面这样使用:-
NSString *aStr = [[NSString alloc] initWithFormat:@"%@,%@",@"Foo",@"Bar"];
NSLog(@"%@",aStr);
您在问"为什么"。除了您忽略的答案"在同一对象上调用init两次是baaaad"之外,NSString是一个类集群。
[NSString alloc]返回一个泛型对象,该对象实际上不能用作字符串,但需要调用init方法。让我们考虑一下显而易见的事情:NSString对象是不可变的,但[NString-alloc]的结果不可能是不可变,因为否则就不可能存储值,对吧?
该init方法实际上将返回一个不再接受init方法的不同对象。虽然[NString-alloc]是一个非常灵活的对象,可以做任何事情,但在调用init方法后,您会得到一个对象,其中包含一个永远不能再修改的字符串。
(苹果可能已经实现了与我所说的不同的东西,或者可能会改变他们的实现方式。尽管如此,他们可以也会做一些事情来阻止你做愚蠢的事情)。
还有一个警告:甚至不要想子类化NSString。我可以保证你不会拼凑出任何有用的东西。