Ios 如何实现apple集群模式中的行为(NSString和NSCFString)
我只是为了测试目的编写以下代码:Ios 如何实现apple集群模式中的行为(NSString和NSCFString),ios,objective-c,nsstring,Ios,Objective C,Nsstring,我只是为了测试目的编写以下代码: 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 __NSCFS
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
通过google,我知道initWithFormat
将返回NSCFString
对象。
我的问题是,如果
NSCFString
是NSString
的派生类,那么为什么我不能在NSCFString
上调用initWithFormat
方法。如果可以停止可见性,如何在代码中实现。NSCFString
和NSCFConstantString
接口是私有的,您不应该使用它们。在查看代码时,很难理解当publicNSString
超类以更简单的方式完成所有需要的工作时,为什么需要深入研究私有子类:
NSString *aStr = @"Foo";
aStr = @"Bar";
或者,如果需要使用以下格式:
NSString *aStr = [NSString stringWithFormat:@"Foo"];
NSCFString
和NSCFConstantString
接口是私有的,您不应该使用它们。在查看代码时,很难理解当publicNSString
超类以更简单的方式完成所有需要的工作时,为什么需要深入研究私有子类:
NSString *aStr = @"Foo";
aStr = @"Bar";
或者,如果需要使用以下格式:
NSString *aStr = [NSString stringWithFormat:@"Foo"];
问题是您无法重新初始化
NSString
,因为它是一个不可变类,如果您想在创建后更改NSString
,则必须使用NSMutableString
但是,在您的情况下,也可以使用NSString
,如下所示:
NSString *aStr = [[NSString alloc] initWithFormat:@"Foo"];
aStr = [[NSString alloc] initWithFormat:@"Bar"];
不过,最好是:
NSString *aStr = @"Foo";
aStr = @"Bar";
如果您试图添加字符串,您将执行以下操作:
NSMutableString *aStr = [[NSMutableString alloc] initWithString:@"Foo"];
[aStr appendString:@"Bar"];
问题是您无法重新初始化
NSString
,因为它是一个不可变类,如果您想在创建后更改NSString
,则必须使用NSMutableString
但是,在您的情况下,也可以使用NSString
,如下所示:
NSString *aStr = [[NSString alloc] initWithFormat:@"Foo"];
aStr = [[NSString alloc] initWithFormat:@"Bar"];
不过,最好是:
NSString *aStr = @"Foo";
aStr = @"Bar";
如果您试图添加字符串,您将执行以下操作:
NSMutableString *aStr = [[NSMutableString alloc] initWithString:@"Foo"];
[aStr appendString:@"Bar"];
类集群通常由一个公共类和许多派生自公共类的私有子类实现,因此它们具有相同的接口。查一下号码。通过涉及[NSNumber numberWithBool];该方法返回特定于bool的NSNumber子类的实例,而[NSNumber numberwhithint];返回特定于nit的NSNumber子类的实例。它们都具有相同的接口,NSNumber接口。一个类集群通常由一个公共类和许多派生自公共类的私有子类实现,因此它们具有相同的接口。查一下号码。通过涉及[NSNumber numberWithBool];该方法返回特定于bool的NSNumber子类的实例,而[NSNumber numberwhithint];返回特定于nit的NSNumber子类的实例。它们都具有相同的接口,即NSNumber接口。让我们研究一下
NSString
类集群如何在内部工作:
NSString *factory = [NSString alloc];
NSString *theInstance = [factory initWithString:@"I am constant"];
NSLog(@"factory class: %@, instance class: %@", [factory class], [theInstance class]);
输出为:
factory class: NSPlaceholderString, instance class: __NSCFConstantString
如您所见,alloc
方法返回NSPlaceholderString
的实例。它是一个“工厂”类,实现了NSString
中声明的所有init…
方法。这些方法返回NSString
的具体(私有)子类。在本例中,它返回\uu NSCFConstantString
如果您将第一行更改为
NSString *factory = [NSMutableString alloc];
输出将更改为:
NSPlaceholderMutableString,实例类:\uu NSCFString
因此,可变字符串和不可变字符串有不同的工厂类,这些工厂返回不同的子类
您甚至可以检查iOS运行时标题中私有子类的层次结构:和
现在,让我们看看在我们刚刚创建的
\unscfconstantstring
实例上调用initWithString:
时会发生什么
[theInstance initWithString:@"Crash"];
正如你所料,它崩溃了。在stacktrace中,我们可以看到调用了-[NSString initWithCharactersNoCopy:length:freeWhenDone:][/code>方法,引发了一个异常:
“NSInvalidArgumentException”,原因:“***初始化方法”
-initWithCharactersCopy:length:freeWhenDone:无法发送到类uu NSCFConstantString:创建具体对象的抽象对象
实例
所以我们可以猜测,NSString
类中的这个初始值设定项实际上是一个抽象方法(有点-Objective-C中没有抽象方法,所以调用时会抛出异常)
此方法在工厂类NSPlaceholderString
中实现。但是它并没有在所有具体的子类中实现,所以如果调用任何init…
方法,它将调用引发异常的NSString
实现
让我们把它们放在一起,构建NSString
类集群的一小部分。它非常简单,可能与实际实现完全不同,但我只是想展示一下这个想法
@interface NSPlaceholderString : NSString
@end
@interface __NSCFConstantString : NSString
@end
@implementation NSString
+ (instancetype)alloc {
return [[NSPlaceholderString alloc] init];
}
- (instancetype)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer {
[NSException raise:NSInvalidArgumentException format:@" initialization method -initWithCharactersNoCopy:length:freeWhenDone: cannot be sent to an abstract object of class %@: Create a concrete instance!'", [self class]];
return nil;
}
- (instancetype)initWithString:(NSString *)aString {
//this method has to call the "abstract" initializer somewhere. The real implementation is probably more complex, this single line is here for simplicity
return [self initWithCharactersNoCopy:[aString UTF8String] length:[aString length] freeWhenDone:YES];
}
@end
@implementation NSPlaceholderString
- (instancetype)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer {
__NSCFConstantString *concreteClassInstance = ...; // create the concrete instance.
return concreteClassInstance;
}
@end
@implementation __NSCFConstantString
//implement all the needed methods here. But do NOT implement initWithCharactersNoCopy:length:freeWhenDone:
@end
让我们研究一下NSString
类集群在内部是如何工作的:
NSString *factory = [NSString alloc];
NSString *theInstance = [factory initWithString:@"I am constant"];
NSLog(@"factory class: %@, instance class: %@", [factory class], [theInstance class]);
输出为:
factory class: NSPlaceholderString, instance class: __NSCFConstantString
如您所见,alloc
方法返回NSPlaceholderString
的实例。它是一个“工厂”类,实现了NSString
中声明的所有init…
方法。这些方法返回NSString
的具体(私有)子类。在本例中,它返回\uu NSCFConstantString
如果您将第一行更改为
NSString *factory = [NSMutableString alloc];
输出将更改为:
NSPlaceholderMutableString,实例类:\uu NSCFString
因此,可变字符串和不可变字符串有不同的工厂类,这些工厂返回不同的子类
你甚至可以检查公关的层次结构