3 回答

TA貢獻1946條經(jīng)驗 獲得超3個贊
Objective-C委托是已將delegate
另一個對象分配給屬性的對象。要創(chuàng)建一個,只需定義一個實現(xiàn)您感興趣的委托方法的類,并將該類標記為實現(xiàn)委托協(xié)議。
例如,假設(shè)你有一個UIWebView
。如果你想實現(xiàn)它的委托webViewDidStartLoad:
方法,你可以創(chuàng)建一個這樣的類:
@interface MyClass<UIWebViewDelegate>// ...@end@implementation MyClass- (void)webViewDidStartLoad:(UIWebView *)webView { // ... }@end
然后,您可以創(chuàng)建MyClass的實例并將其指定為Web視圖的委托:
MyClass *instanceOfMyClass = [[MyClass alloc] init];myWebView.delegate = instanceOfMyClass;
另一方面UIWebView
,它可能具有與此類似的代碼,以查看委托是否響應(yīng)webViewDidStartLoad:
消息respondsToSelector:
并在適當時發(fā)送它。
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { [self.delegate webViewDidStartLoad:self];}
委托屬性本身通常聲明weak
(在ARC中)或assign
(預(yù)ARC)以避免保留循環(huán),因為對象的委托通常持有對該對象的強引用。(例如,視圖控制器通常是它包含的視圖的委托。)
為您的類創(chuàng)建代表
要定義自己的委托,您必須在某處聲明其方法,如Apple Docs on protocols中所述。您通常會聲明一個正式的協(xié)議。從UIWebView.h轉(zhuǎn)述的聲明如下所示:
@protocol UIWebViewDelegate <NSObject>@optional- (void)webViewDidStartLoad:(UIWebView *)webView;// ... other methods here@end
這類似于接口或抽象基類,因為它為您的委托創(chuàng)建了一種特殊類型,UIWebViewDelegate
在本例中。代表實施者必須采用該協(xié)議:
@interface MyClass <UIWebViewDelegate>// ...@end
然后實現(xiàn)協(xié)議中的方法。對于在協(xié)議中聲明的方法@optional
(與大多數(shù)委托方法一樣),您需要-respondsToSelector:
在調(diào)用特定方法之前進行檢查。
命名
委托方法通常以委托類名稱開頭命名,并將委托對象作為第一個參數(shù)。他們也經(jīng)常使用意志,應(yīng)該或形式。因此,webViewDidStartLoad:
(第一個參數(shù)是Web視圖)而不是loadStarted
(不帶參數(shù))。
速度優(yōu)化
每次我們想要給它發(fā)消息時,不是檢查委托是否響應(yīng)選擇器,而是在設(shè)置委托時緩存該信息。一個非常干凈的方法是使用位域,如下所示:
@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
結(jié)構(gòu)來處理消息,而不是-respondsToSelector:
一遍又一遍地發(fā)送。
非正式代表
協(xié)議出現(xiàn)之前,它是共同使用類別上NSObject
宣布委托可以實現(xiàn)的方法。例如,CALayer
仍然這樣做:
@interface NSObject(CALayerDelegate)- (void)displayLayer:(CALayer *)layer;// ... other methods here@end
這基本上告訴編譯器任何對象都可以實現(xiàn)displayLayer:
。
然后,您將使用與上述相同的-respondsToSelector:
方法來調(diào)用此方法。代理只需實現(xiàn)此方法并分配delegate
屬性,就是它(沒有聲明您符合協(xié)議)。這種方法在Apple的庫中很常見,但是新代碼應(yīng)該使用上面更現(xiàn)代的協(xié)議方法,因為這種方法會污染NSObject
(這使得自動完成功能不那么有用)并且使編譯器很難警告你有關(guān)拼寫錯誤和類似錯誤的信息。

TA貢獻1772條經(jīng)驗 獲得超5個贊
當使用正式協(xié)議方法創(chuàng)建委托支持時,我發(fā)現(xiàn)您可以通過添加以下內(nèi)容來確保正確的類型檢查(盡管是運行時,而不是編譯時):
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 關(guān)注
- 738 瀏覽
添加回答
舉報