如何在Objective-C中创建委托? [英] How do I create delegates in Objective-C?

查看:108
本文介绍了如何在Objective-C中创建委托?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道代表如何工作,我知道如何使用它们。



但是如何创建呢?

委托属性另一个对象的对象。要创建一个,你只需定义一个类,实现你感兴趣的委托方法,并将该类标记为实现委托协议。



例如,假设你有一个 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:消息使用 respondingToSelector:并在适当时发送。

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

委托属性本身通常被声明为 weak (在ARC中)或 assign (pre-ARC)以避免保留循环,因为对象的委托通常持有对该对象的强引用。 (例如,视图控制器通常是其包含的视图的委托。)



为您的类创建委派



要定义自己的代理,您必须在某处声明他们的方法,如 Apple Docs on protocols 。您通常声明一个正式协议。从UIWebView.h释义的声明如下:

  @protocol UIWebViewDelegate< NSObject> 
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ...这里的其他方法
@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>代表;
@end

@implementation某事{
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 responsesToSelector:@selector(something:didFinishLoadingItem :)];
delegateRespondsTo.didFailWithError = [delegate responsesToSelector:@selector(something:didFailWithError :)];
}
}
@end

,我们可以通过访问我们的 delegateRespondsTo 结构来检查我们的代理处理消息,而不是发送 -respondsToSelector:



非正式代表



在协议存在之前,通常使用类别 NSObject 来声明一个委托可以实现的方法。例如, CALayer 仍然这样做:

  @interface NSObject(CALayerDelegate )
- (void)displayLayer:(CALayer *)layer;
// ...这里的其他方法
@end

任何对象可能实现 displayLayer:的编译器。



-respondsToSelector:方法调用此方法。代理只需实现此方法并分配 delegate 属性,就是它(没有声明你符合协议)。这种方法在苹果的库中很常见,但是新代码应该使用上面更现代的协议方法,因为这种方法污染了 NSObject (这使得自动完成不太有用)编译器警告您有关错误和类似错误。


I know how delegates work, and I know how I can use them.

But how do I create them?

解决方案

An Objective-C delegate is an object that has been assigned to the delegate property another object. To create one, you simply define a class that implements the delegate methods you're interested in, and mark that class as implementing the delegate protocol.

For example, suppose you have an UIWebView. If you'd like to implement its delegate's webViewDidStartLoad: method, you could create a class like this:

@interface MyClass<UIWebViewDelegate>
// ...
@end

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end

Then you could create an instance of MyClass and assign it as the web view's delegate:

MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;

On the UIWebView side, it probably has code similar to this to see if the delegate responds to the webViewDidStartLoad: message using respondsToSelector: and send it if appropriate.

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

The delegate property itself is typically declared weak (in ARC) or assign (pre-ARC) to avoid retain loops, since the delegate of an object often holds a strong reference to that object. (For example, a view controller is often the delegate of a view it contains.)

Making Delegates for Your Classes

To define your own delegates, you'll have to declare their methods somewhere, as discussed in the Apple Docs on protocols. You usually declare a formal protocol. The declaration, paraphrased from UIWebView.h, would look like this:

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

This is analogous to an interface or abstract base class, as it creates a special type for your delegate, UIWebViewDelegate in this case. Delegate implementors would have to adopt this protocol:

@interface MyClass <UIWebViewDelegate>
// ...
@end

And then implement the methods in the protocol. For methods declared in the protocol as @optional (like most delegate methods), you need to check with -respondsToSelector: before calling a particular method on it.

Naming

Delegate methods are typically named starting with the delegating class name, and take the delegating object as the first parameter. They also often use a will-, should-, or did- form. So, webViewDidStartLoad: (first parameter is the web view) rather than loadStarted (taking no parameters) for example.

Speed Optimizations

Instead of checking whether a delegate responds to a selector every time we want to message it, you can cache that information when delegates are set. One very clean way to do this is to use a bitfield, as follows:

@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

Then, in the body, we can check that our delegate handles messages by accessing our delegateRespondsTo struct, rather than by sending -respondsToSelector: over and over again.

Informal Delegates

Before protocols existed, it was common to use a category on NSObject to declare the methods a delegate could implement. For example, CALayer still does this:

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

This essentially tells the compiler that any object might implement displayLayer:.

You would then use the same -respondsToSelector: approach as described above to call this method. Delegates simply implement this method and assign the delegate property, and that's it (there's no declaring you conform to a protocol). This method is common in Apple's libraries, but new code should use the more modern protocol approach above, since this approach pollutes NSObject (which makes autocomplete less useful) and makes it hard for the compiler to warn you about typos and similar errors.

这篇关于如何在Objective-C中创建委托?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆