我知道代理如何工作,我知道如何使用它们
但是我如何创建它们呢
Objective-C委托是已分配给另一个对象的委托属性的对象。要创建一个类,您需要定义一个实现感兴趣的委托方法的类,并将该类标记为实现委托协议
例如,假设您有一个UIWebView。如果您想实现其委托的webViewDidStartLoad:方法,可以创建如下类:
@接口MyClass<;UIWebViewDelegate>;
// ...
@结束
@MyClass的实现
-(void)webView下载:(UIWebView*)webView{
// ...
}
@结束
然后可以创建MyClass的实例并将其指定为web视图的委托:
MyClass*instanceOfMyClass=[[MyClass alloc]init];
myWebView.delegate=instanceOfMyClass;
在UIWebView端,它可能有类似的代码,以查看代理是否使用respondsToSelector:响应webview加载:消息,并在适当时发送它
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)])){
[self.delegate webview加载:self];
}
委托属性本身通常声明为弱(在弧中)或赋值(弧前)以避免保留循环,因为对象的委托通常包含对该对象的强引用。(例如,视图控制器通常是其包含的视图的委托。)
为您的课程制作代理
要定义您自己的委托,您必须在某个地方声明它们的方法,如Apple协议文档中所述。您通常声明一个正式的协议。从UIWebView.h转述的声明如下:
@protocol UIWebViewDelegate<;NSObject>;
@可选的
-(void)webView加载:(UIWebView*)webView;
// ... 这里还有其他方法
@结束
这类似于接口或抽象基类,因为它为您的委托创建了一种特殊类型,在本例中为UIWebViewDelegate。代理实施者必须采用以下协议:
@接口MyClass<;UIWebViewDelegate>;
// ...
@结束
然后实现协议中的方法。对于协议中声明为@optional(与大多数委托方法一样)的方法,在调用特定方法之前,需要使用-respondsToSelector:进行检查
命名
委托方法通常以委托类名开始命名,并将委托对象作为第一个参数。他们也经常使用意愿、应该或做过的形式。例如,webviewdistart加载:(第一个参数是web视图),而不是loadStarted(不带参数)
速度优化
您可以在设置代理时缓存该信息,而不是每次我们要发送消息时检查代理是否响应选择器。一种非常干净的方法是使用位字段,如下所示:
@协议SomethingDelegate<;NSObject>;
@可选的
-(void)某物:(id)某物未完成加载项:(id)项;
-(void)某物:(id)某物出错:(n错误*)错误;
@结束
@接口:NSObject
@属性(非原子,弱)id<;SomethingDelegate>;代表
@结束
@实现某事{
结构{
未签名的int-didFinishLoadingItem:1;
无符号整数错误:1;
}授权响应;
}
@综合代表;
-(void)setDelegate:(id<;SomethingDelegate>;)代理{
如果(委托人!=代理人){
代表=大使;
delegateRespondsTo.didFinishLoadingItem=[delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError=[delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@结束
然后,在主体中,我们可以通过访问delegateRespondsTostruct,而不是通过反复发送-respondsToSelector:来检查我们的委托是否处理消息
非正式代表
在协议存在之前,通常使用NSObject上的类别来声明委托可以实现的方法。例如,CALayer仍然执行以下操作:
接口NSObject(CALayerDelegate)
-(void)显示层:(CALayer*)层;
// … 这里还有其他方法
@结束
这告诉编译器任何对象都可能实现displayLayer:
然后使用与上述相同的-respondsToSelector:方法调用此方法。代理实现此方法并分配delegate属性,就是它(没有声明您符合协议)。这种方法在苹果的库中很常见,但是新代码应该使用上面更现代的协议方法,因为这种方法污染了NSObject(这使得autocomplete不那么有用),并且使编译器很难警告您输入错误和类似错误