Objective-C 方法与 Java 或 C++ 方法不同。它们是消息,它们独立于任何类或对象而存在。当您在 Photo.h 中编写(取自CocoaDevCentral)时:
#import <Cocoa/Cocoa.h>
@interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
- caption;
- photographer;
@end
你是说这个Photo
类有一个标题和一个摄影师对象,它会响应消息caption
和photographer
. 那是为这两个项目编写代码的旧的 pre-properties 方式。
您将编写代码来Photo.m
给出这两条消息的实现,以便 aPhoto
可以响应它们。但是没有什么能阻止你发送caption
到任何对象。这就像一部关于我们对狗说什么以及它们听到什么的老远方卡通片。任何错误都会在运行时发生。
那么,当您向不知道如何响应的对象发送消息时会发生什么?如果你没有做任何特别的事情,
- 运行时系统将消息打包成一个类型的事物
SEL
。
- 它
doesNotRecognizeSelector:
使用该选择器将消息发送到对象。
- 该对象继承自
NSObject
引发NSInvalidArgumentException
.
但是,在此之前有一些机会可以通过覆盖方法进行干预:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
这使您可以在运行时安装实现。
- (id)forwardingTargetForSelector:(SEL)aSelector
这使您可以指定另一个对象来接受该消息。
- (void)forwardInvocation:(NSInvocation *)anInvocation
这使您可以以任何方式处理消息。
在 Objective-C 获得块之前,有许多库使用转发进行函数式编程。假设您有一个都理解该消息的NSArray
of s。假设您想收集另一个帐户中所有帐户的余额。该库没有循环,而是提供了一个带有消息的类别,您可以编写:Account
balance
NSArray
NSArray
collect
NSArray *accounts = ...;
NSArray *balances = [[accounts collect] balance];
的结果[accounts collect]
没有balance
消息的实现;怎么可能? collect
由图书馆提供。相反,它有一个forwardInvocation:
实现,将balance
消息发送给 的所有成员,并从中accounts
创建一个新成员。NSArray
如今,人们可能会使用积木enumerateObjectsUsingBlock:
,但这是一种非常简洁而强大的技术。