让我们调查一下如何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
。它是一个“工厂”类,它实现了所有init...
中声明的方法NSString
。这些方法返回具体(私有)子类NSString
。它返回__NSCFConstantString
在这个例子中。
如果将第一行更改为
NSString *factory = [NSMutableString alloc];
输出将更改为:
NSPlaceholderMutableString,实例类:__NSCFString
因此,可变和不可变字符串有不同的工厂类,并且这些工厂返回不同的子类。
您甚至可以检查 iOS 运行时标头中私有子类的层次结构:here and here.
现在让我们看看当我们调用时会发生什么initWithString:
在一个实例上__NSCFConstantString
我们刚刚创建。
[theInstance initWithString:@"Crash"];
正如你所预料的 - 它崩溃了。在堆栈跟踪中我们可以看到-[NSString initWithCharactersNoCopy:length:freeWhenDone:]
方法被调用,抛出异常:
'NSInvalidArgumentException',原因:'***初始化方法
-initWithCharactersNoCopy:length:freeWhenDone: 无法发送到类 __NSCFConstantString 的抽象对象: 创建一个具体的对象
实例!'
所以我们可以猜测这个初始化器在NSString
class 实际上是一个抽象方法(有点 - Objective-C 中没有抽象方法,因此在调用时会抛出异常)。
该方法在工厂类中实现NSPlaceholderString
。但它是not在所有具体子类中实现,因此如果您调用任何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