[爆棧熱門 iOS 問題] 如何寫好一個 delegate

系列文集:爆棧熱門 iOS 問題目錄在此。倉薯翻譯,歡迎指正:)

問題

我知道 delegate 機制是怎么回事,也知道怎么用 delegate。但是自己寫一個 delegate 需要注意什么呢?


答案

Jesse Rusak,723 贊

我把他答案的要點摘錄如下:

用 weak

保存 delegate 屬性在 ARC 里要用weak來防止循環(huán)引用,因為一個對象的 delegate 往往持有這個對象本身。(比如,viewController 經(jīng)常會當它里面子 view 的 delegate。)

要檢查 @optional 方法是否實現(xiàn)

聲明 protocol 一般是這樣:

@protocol UIWebViewDelegate <NSObject>
// Declaration for Methods that 'must' be implemented'
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

大部分 delegate 方法都是@optional的。@optional的方法在調(diào)用之前要用-respondsToSelector:檢查一下 delegate 對這個方法真正實現(xiàn)了沒有。比如在UIWebView里應該有類似如下的代碼:

if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { 
    [self.delegate webViewDidStartLoad:self];
}

命名

delegate 方法一般以依靠 delegate 的類名開頭,然后把依靠 delegate 的對象用第一個參數(shù)傳進去。方法名一般常用will-、should-、did-這些詞。比如,webViewDidStartLoad:(參數(shù)就是那個 webView)就要比loadStarted(沒參數(shù))好得多。

性能小優(yōu)化

為了不用每調(diào)一次方法之前都要用respondsToSelector:來檢查這個方法有沒有實現(xiàn),我們可以在設 delegate 的時候就檢查哪些方法實現(xiàn)了、哪些沒實現(xiàn),然后緩存下來。最簡潔的辦法就是用一個標志位來保存,如下:

@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end

@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end

@implementation Something {
    struct {
        unsigned int didFinishLoadingItem:1;
        unsigned int didFailWithError:1;
    } delegateRespondsTo;
}
@synthesize delegate;

- (void)setDelegate:(id <JSSomethingDelegate>)aDelegate {
    if (delegate != aDelegate) {
        delegate = aDelegate;

        delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
        delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

這樣,在要調(diào) delegate 方法的時候,我們就可以直接檢查delegateRespondsTo 結(jié)構(gòu)體的屬性,不用再一遍又一遍調(diào)-respondsToSelector:了。

簡寫的 delegate

在有 protocol 之前,一般是給 NSObject 加一個 category 來聲明 delegate 可以實現(xiàn)的方法。比如,現(xiàn)如今CALayer還有:

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

意思是告訴編譯器,任何對象都可以實現(xiàn)displayLayer:方法。

如果這樣寫的話,在調(diào)用方法之前也要同樣要用上面提到的-respondsToSelector:來檢查。只要讓 delegate 對象實現(xiàn)這個方法,然后把它保存在delegate屬性里就行了,不用寫 protocol 什么的。蘋果官方的庫里有不少這樣的東西,但是新寫的代碼最好還是用上面聲明 protocol 的正規(guī)寫法。因為這種簡寫方法會污染NSObject(會干擾代碼自動補全),并且也讓編譯器不易檢查出打錯字之類的 error。

原文地址:How do I create delegates in Objective-C?

本文地址:http://www.itdecent.cn/p/42f42bed16cf

系列文集:爆棧熱門 iOS 問題

譯者:@戴倉薯

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容