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

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

问题描述

我知道委托是如何工作的,我知道如何使用它们.

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

但我如何创建它们?

推荐答案

Objective-C 委托是已分配给另一个对象的 delegate 属性的对象.要创建一个,您需要定义一个实现您感兴趣的委托方法的类,并将该类标记为实现委托协议.

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

例如,假设您有一个 UIWebView.如果您想实现其委托的 webViewDidStartLoad: 方法,你可以创建一个这样的类:

For example, suppose you have a 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

然后你可以创建一个 MyClass 的实例并将它分配为 web 视图的委托:

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;

UIWebView 端,它可能有类似的代码来查看委托是否使用 respondsToSelector: 并在适当时发送.

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];
}

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

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.)

要定义自己的委托,您必须在某处声明他们的方法,如 Apple Docs on协议.你通常会声明一个正式的协议.从 UIWebView.h 转述的声明将如下所示:

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

这类似于接口或抽象基类,因为它为您的委托创建了一个特殊类型,在本例中为 UIWebViewDelegate.委托实现者必须采用此协议:

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

然后实现协议中的方法.对于在协议中声明为 @optional 的方法(与大多数委托方法一样),您需要在调用特定方法之前使用 -respondsToSelector: 检查.

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.

委托方法通常以委托类名开头命名,并以委托对象作为第一个参数.他们还经常使用 will-、should- 或 did- 形式.因此,例如 webViewDidStartLoad:(第一个参数是 Web 视图)而不是 loadStarted(不带参数).

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.

不是每次我们想要给选择器发送消息时都检查委托是否响应选择器,您可以在设置委托时缓存该信息.一种非常简洁的方法是使用位域,如下所示:

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 <SomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

然后,在正文中,我们可以通过访问我们的 delegateRespondsTo 结构来检查我们的委托是否处理消息,而不是通过一遍又一遍地发送 -respondsToSelector:.

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.

在协议存在之前,通常使用 NSObject 上的 "noreferrer">category 来声明委托可以实现的方法.例如,CALayer 仍然这样做:

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

这告诉编译器任何对象都可能实现displayLayer:.

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

然后您将使用与上述相同的 -respondsToSelector: 方法来调用此方法.委托实现此方法并分配 delegate 属性,仅此而已(没有声明您遵守协议).这种方法在 Apple 的库中很常见,但新代码应该使用上面更现代的协议方法,因为这种方法会污染 NSObject(这使得自动完成不太有用)并使编译器难以警告你错别字和类似错误.

You would then use the same -respondsToSelector: approach as described above to call this method. Delegates 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天全站免登陆