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 瀏覽
添加回答
舉報