让我们来研究一下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 的具体(私有)子类。在此示例中,它返回 __NSCFConstantString。
如果你把第一行改成
NSString *factory = [NSMutableString alloc];
输出将变为:
NSPlaceholderMutableString,实例类:__NSCFString
所以可变字符串和不可变字符串有不同的工厂类,这些工厂返回不同的子类。
您甚至可以检查 iOS 运行时标头中私有子类的层次结构:here 和 here。
现在让我们看看当我们在刚刚创建的__NSCFConstantString 实例上调用initWithString: 时会发生什么。
[theInstance initWithString:@"Crash"];
如您所料 - 它崩溃了。在stacktrace中我们可以看到-[NSString initWithCharactersNoCopy:length:freeWhenDone:]方法被调用,抛出异常:
'NSInvalidArgumentException',原因:'***初始化方法
-initWithCharactersNoCopy:length:freeWhenDone: 不能发送到类的抽象对象 __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