24 浏览
0 Comments

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

但是我该如何创建它们呢?

admin 更改状态以发布 2023年5月23日
0
0 Comments

批准的答案很棒,但如果你正在寻找一个1分钟的答案,请尝试以下方法:

MyClass.h文件应该像这样(添加带有注释的委托行!)

#import 
@class MyClass;             //define class, so protocol can see MyClass
@protocol MyClassDelegate    //define delegate protocol
    - (void) myClassDelegateMethod: (MyClass *) sender;  //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id  delegate; //define MyClassDelegate as delegate
@end

MyClass.m文件应该如下

#import "MyClass.h"
@implementation MyClass 
@synthesize delegate; //synthesise  MyClassDelegate delegate
- (void) myMethodToDoStuff {
    [self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class    
}
@end

在另一个类(在这种情况下,称为MyVC的UIViewController)中使用您的代理MyVC.h:

#import "MyClass.h"
@interface MyVC:UIViewController  { //make it a delegate for MyClassDelegate
}

MyVC.m:

myClass.delegate = self;          //set its delegate to self somewhere

实现委托方法

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

0
0 Comments

Objective-C的代理是被分配到另一个对象的delegate属性的对象。要创建一个代理,您可以定义一个类来实现您感兴趣的代理方法,并将该类标记为实现代理协议。

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

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

然后,您可以创建MyClass的实例并将其分配为web视图的代理:

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

UIWebView方面,它可能有类似于以下代码的代码,以查看代理是否对于webViewDidStartLoad:消息做出反应,使用respondsToSelector:以及在适当时发送它。

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

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

为您的类制作代理

为了定义自己的代理,你需要在某个地方声明它们的方法,就像在Apple docs on protocols中所讨论的那样。您通常声明一个正式协议。该声明(从UIWebView.h派生)如下所示:

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

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

@interface MyClass 
// ...
@end

然后实现协议中的方法。对于在协议中声明为@optional的方法(如大多数代理方法),您需要在调用特定方法之前使用-respondsToSelector:进行检查。

命名

代理方法通常以委托类名开头,以委托对象作为第一个参数。它们还经常使用will-,should-或did-形式。例如,webViewDidStartLoad:(第一个参数是web视图)而不是loadStarted(不带参数)。

速度优化

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

@protocol SomethingDelegate 
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id  delegate;
@end
@implementation Something {
  struct {
    unsigned int didFinishLoadingItem:1;
    unsigned int didFailWithError:1;
  } delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id )aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;
    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

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

非正式代理

在协议出现之前,常常使用NSObject的一个类别来声明代理可以实现的方法。例如,CALayer仍然使用这种方法:

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

这告诉编译器,任何对象都可以实现displayLayer:方法。

然后,您会使用上面描述的相同的-respondsToSelector:方法来调用此方法。委托实现此方法并分配delegate属性,就完成了这一操作(不需要声明您符合协议)。这种方法在Apple的库中很常见,但新的代码应该使用上面更现代的协议方法,因为这种方法会污染NSObject(使自动完成不太有用)并使编译器很难警告您有关拼写错误和类似错误的内容。

0