您的類別是確定的,但非常靈活。委託回調應該至少包含至少一個參數(調用對象),並且您的方法不允許使用參數。委託方法也經常返回值,這種方法也不允許。
正如Stephen指出的,正確的代碼不應該使用performSelector:
,而應該直接調用該方法。這具有編譯時檢查拼寫錯誤的優點,特別是如果再加上我強烈建議的「Undeclared Selector」警告選項(GCC_WARN_UNDECLARED_SELECTOR)。
如果輸入是一個問題,那麼解決方案就是一個蹦牀。問題在於蹦牀比調用方法要慢得多,但它們很方便。例如,下面是你正在談論的一個例子。 (我沒有測試過;它從一個更復雜的我用來發送消息給多個代表的過程中被剝離了下來,在這裏更值得)。
#import <objc/runtime.h>
@interface RNDelegateTrampoline : NSObject {
@private
id delegate_;
Protocol *protocol_;
}
@property (nonatomic, readwrite, assign) id delegate;
@property (nonatomic, readwrite, retain) Protocol *protocol;
- (id)initWithProtocol:(Protocol *)aProtocol delegate:(id)aDelegate;
@end
@implementation RNDelegateTrampoline
- (id)initWithProtocol:(Protocol *)aProtocol delegate:(id)aDelegate {
if ((self = [super init])) {
protocol_ = [aProtocol retain];
delegate_ = aDelegate;
}
return self;
}
- (void)dealloc {
[protocol_ release], protocol_ = nil;
delegate_ = nil;
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
// Look for a required method
struct objc_method_description desc = protocol_getMethodDescription(self.protocol, selector, YES, YES);
if (desc.name == NULL) {
// Maybe it's optional
desc = protocol_getMethodDescription(self.protocol, selector, NO, YES);
}
if (desc.name == NULL) {
[self doesNotRecognizeSelector:selector]; // Raises NSInvalidArgumentException
return nil;
}
else {
return [NSMethodSignature signatureWithObjCTypes:desc.types];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if ([[self delegate] respondsToSelector:[invocation selector]]) {
[invocation invokeWithTarget:[self delegate]];
}
}
@synthesize delegate = delegate_;
@synthesize protocol = protocol_;
@end
你會再使用這樣的:
@property (nonatomic, readwrite, retain) id delegateTramp;
self.delegateTramp = [[[RNDelegateTrampoline alloc] initWithProtocol:@protocol(ThisObjectDelegate) delegate:aDelegate] autorelease];
...
[self.delegateTramp thisObject:self didSomethingWith:x];
請注意,我們使用id
而不是RNDelegateTrampoline
作爲我們的代表蹦牀的類型。這很重要,否則你會收到編譯器警告,你試圖發送給它的任何東西。聲明它爲id
克服了這一點。當然,如果將未知方法傳遞給委託,它也會拋出編譯時警告。不過,您仍然會遇到運行時異常。
這是我想到的「更智能的解決方案」(儘管這很可能不值得麻煩)。謝謝! – zoul 2010-11-23 16:01:57