二次指派
在C++,你不需要发送消息,你可以调用成员方法。这是个重要区分,因为这意味着调用方法语义上近似于函数调用。Objective-C对抽象新增加一层。如果你给Objective-C对象发送消息,而这个对象不能解析,将会抛出一个异常。然而,这并不是通过语言做的。
运行时库当对于选择器没找到方法时有个回滚机制。它调用一个方法,这个方法对一些类型信息内省接收器,在一个NSInovocation包装调用,然后给对象传-forwardInvocation:方法。
NSInovocation对象包装了接收器,选择器,和参数。对于高位信息你可以使用这种思想。考虑下面的例子用例:
[[anArray map] toUppercase];
在数组上-map方法返回一个代理对象,这个对象带有forwardInvocation: 方法实现这样:
- (void) forwardInvocation:(NSInvocation*)anInvocation
{
SEL selector = [anInvocation selector];
NSMutableArray * mappedArray = [NSMutableArray array];
FOREACHI(array, object)
{
if([object respondsToSelector:selector])
{
[anInvocation invokeWithTarget:object];
id mapped;
[anInvocation getReturnValue:&mapped];
[mappedArray addObject:mapped];
}
}
[anInvocation setReturnValue:mappedArray];
}
{
SEL selector = [anInvocation selector];
NSMutableArray * mappedArray = [NSMutableArray array];
FOREACHI(array, object)
{
if([object respondsToSelector:selector])
{
[anInvocation invokeWithTarget:object];
id mapped;
[anInvocation getReturnValue:&mapped];
[mappedArray addObject:mapped];
}
}
[anInvocation setReturnValue:mappedArray];
}
FOREACHI宏来自étoilé,并且在NSEnumerator上执行一些IMP缓存。当你发送-toUppercase消息给映射代理,它会迭代数组中每个对象;检查是否回应了选择器,如果回应了,调用带参数的方法。返回值添加到新的数组中。
这在C++是不可能实现的。你可以使用命令模式做一些类似的工作,但只能在C++的头部实现你自己的委派机制。
总结
Objective-C是一个非常小的语言,并且在这个系列里我们涵盖了很多内容,包括一些高级特性。然而,正如Smalltalk,也稍微有些欺骗性。Objective-C语言的核心非常简单,一些Objective-C行为来自库。这通常是OpenStep规格的一个实现,类似GNUstep或者Apple的Cocoa,并且熟悉库的话可以带来长久的成就。