3 回答
TA貢獻1946條經驗 獲得超3個贊
Objective-C委托是已將delegate另一個對象分配給屬性的對象。要創建一個,只需定義一個實現您感興趣的委托方法的類,并將該類標記為實現委托協議。
例如,假設你有一個UIWebView。如果你想實現它的委托webViewDidStartLoad:方法,你可以創建一個這樣的類:
@interface MyClass<UIWebViewDelegate>// ...@end@implementation MyClass- (void)webViewDidStartLoad:(UIWebView *)webView {
// ... }@end然后,您可以創建MyClass的實例并將其指定為Web視圖的委托:
MyClass *instanceOfMyClass = [[MyClass alloc] init];myWebView.delegate = instanceOfMyClass;
另一方面UIWebView,它可能具有與此類似的代碼,以查看委托是否響應webViewDidStartLoad:消息respondsToSelector:并在適當時發送它。
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];}委托屬性本身通常聲明weak(在ARC中)或assign(預ARC)以避免保留循環,因為對象的委托通常持有對該對象的強引用。(例如,視圖控制器通常是它包含的視圖的委托。)
為您的類創建代表
要定義自己的委托,您必須在某處聲明其方法,如Apple Docs on protocols中所述。您通常會聲明一個正式的協議。從UIWebView.h轉述的聲明如下所示:
@protocol UIWebViewDelegate <NSObject>@optional- (void)webViewDidStartLoad:(UIWebView *)webView;// ... other methods here@end
這類似于接口或抽象基類,因為它為您的委托創建了一種特殊類型,UIWebViewDelegate在本例中。代表實施者必須采用該協議:
@interface MyClass <UIWebViewDelegate>// ...@end
然后實現協議中的方法。對于在協議中聲明的方法@optional(與大多數委托方法一樣),您需要-respondsToSelector:在調用特定方法之前進行檢查。
命名
委托方法通常以委托類名稱開頭命名,并將委托對象作為第一個參數。他們也經常使用意志,應該或形式。因此,webViewDidStartLoad:(第一個參數是Web視圖)而不是loadStarted(不帶參數)。
速度優化
每次我們想要給它發消息時,不是檢查委托是否響應選擇器,而是在設置委托時緩存該信息。一個非常干凈的方法是使用位域,如下所示:
@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 <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}}@end然后,在正文中,我們可以檢查我們的委托通過訪問我們的delegateRespondsTo結構來處理消息,而不是-respondsToSelector:一遍又一遍地發送。
非正式代表
協議出現之前,它是共同使用類別上NSObject宣布委托可以實現的方法。例如,CALayer仍然這樣做:
@interface NSObject(CALayerDelegate)- (void)displayLayer:(CALayer *)layer;// ... other methods here@end
這基本上告訴編譯器任何對象都可以實現displayLayer:。
然后,您將使用與上述相同的-respondsToSelector:方法來調用此方法。代理只需實現此方法并分配delegate屬性,就是它(沒有聲明您符合協議)。這種方法在Apple的庫中很常見,但是新代碼應該使用上面更現代的協議方法,因為這種方法會污染NSObject(這使得自動完成功能不那么有用)并且使編譯器很難警告你有關拼寫錯誤和類似錯誤的信息。
TA貢獻1772條經驗 獲得超5個贊
當使用正式協議方法創建委托支持時,我發現您可以通過添加以下內容來確保正確的類型檢查(盡管是運行時,而不是編譯時):
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];}在您的委托訪問器(setDelegate)代碼中。這有助于減少錯誤。
- 3 回答
- 0 關注
- 741 瀏覽
添加回答
舉報
