如何在Objective-C中创建委托?

20 浏览
0 Comments

如何在Objective-C中创建委托?

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

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

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的实例并将其指定为WebView的代理:

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

UIWebView方面,它可能有类似于以下内容的代码,以查看代理是否使用respondsToSelector:响应webViewDidStartLoad:消息并在适当的时候发送它。

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

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

为您的类创建代理

要定义您自己的代理,您必须要在某个地方声明它们的方法,就像在Apple关于协议的文档中讨论的那样。通常情况下,您会声明正式的协议。从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 上的< a href =“ http://www.google.ca/search?q=site:developer.apple.com+category+objective+c&btnI” rel =“noreferrer”>类别来声明委托可以实现的方法。例如, CALayer 仍然在这样做:

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

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

然后,您可以使用与上面描述的相同的 -respondsToSelector: 方法来调用此方法。 代理实现此方法并分配 delegate 属性,就这样(没有声明您符合协议)。 这种方法在苹果的库中很常见,但新代码应使用上面更现代的协议方法,因为这种方法污染了 NSObject(使自动完成变得不太有用)并使它难以警告您有关拼写错误等错误。

0