我如何才能实现与苹果在集群模式中相同的行为(NSString和NSCFString)



我只是为了测试目的而编写以下代码:

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对象。我的问题是,如果NSCFStringNSString的派生类,那么为什么我不能在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。我可以保证你不会拼凑出任何有用的东西。

最新更新