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

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

问题描述

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

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

但是如何创建它们?

推荐答案

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

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.

例如,假设您有一个 UIWebView 。如果您想实施其代理人的 webViewDidStartLoad:方法,您可以创建一个类:

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

然后你可以创建一个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 侧,它可能有代码类似于此,以查看代理是否使用 webViewDidStartLoad:消息基础/协议/ NSObject_Protocol / Reference / NSObject.html#// apple_ref / occ / intfm / NSObject / responsesToSelector:rel =noreferrer> respondToSelector:,并在适当的情况下发送。

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 (pre-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协议。你通常会声明一个正式的协议。来自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.

委托方法通常以委托类名称开头,并将委托对象作为第一个参数。他们也经常使用意志,应该或形式。因此,例如, 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 struct来检查我们的代理,而不是发送 -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 来声明代理可以实现的方法。例如, 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 essentially tells the compiler that any object might implement displayLayer:.

然后您将使用相同的对应的T选择器:方法,如上所述调用此方法。代理人只需实现这个方法并分配委托属性,就是这样(没有声明你符合协议)。这种方法在Apple的库中是常见的,但是新代码应该使用上述更现代化的协议方法,因为这种方法污染了 NSObject (这使得自动完成更少有用)编译器警告您有关打字错误和类似错误。

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天全站免登陆