我知道委托如何工作,我也知道怎么使用。但是我该怎么创建呢?
原文:
How do I create delegates in Objective-C? I know how delegates work, and I know how I can use them. But how do I create them?
I know how delegates work, and I know how I can use them. But how do I create them?
这是问题原文链接
欢迎选择我的课程,让我们一起见证您的进步~~
Objective-C 委托就是已被指定为另一个委托的对象,没有特殊的创建过程,你只要定义一个实现你感兴趣的委托方法的类就可以。(虽然委托使用正式协议,但你必须得声明委托来执行该协议,如下所示) 例如,假设你有个NSWindow。如果你想要实现他的委托的 windowDidMove: 方法,你可以创建一个这样的类:
@implementation MyClass - (void)windowDidMove:(NSNotification*)notification { // ... } @end
然后创建一个MyClass的实例并制定为window的委托:
MyClass *myDelegate = [[MyClass alloc] init]; [window setDelegate: myDelegate];
在NSWindow方面, 可能有类似于此的代码使用 respondsToSelector: 来看委托是否响应windowDidMove:信息,如何合适就发送。
if([[self delegate] respondsToSelector:@selector(windowDidMove:)]) { [[self delegate] windowDidMove:notification]; }
委托资源本身是典型声明的weak(ARC)或assign(预ARC)来避免循环,因为对象委托经常持有强引用该对象(例如,一个视图控制器通常包含视图委托) 要定义自己的委托,你需要在某个地方声明方法。有两个基本的方法,苹果的文档协议有讨论过.
这个就和NSWindow差不多,在NSObject的类别实现。例如,继续上面的例子,这是从NSWindow.h:转述的:
@interface NSObject(NSWindowNotifications) - (void)windowDidMove:(NSNotification *)notification; // ... 其他方法 @end
就像上面描述的那样,当调用这个函数的时候,你会使用-respondsToSelector:,委托简单的实现此方法,就完成了。这个方法在苹果的库里是直接常见的,但是新的代码应该是用下面的更现代的方法。
新的选择是声明一个正式的协议。声明应该像这个样子:
@protocol NSWindowNotifications <NSObject> @optional - (void)windowDidMove:(NSNotification *)notification; // ...其他方法 @end
这类似于一个借口或者抽象基类,因为这为委托建立了一个特殊的类型,这种情况下是NSWindowNotifications。委托执行者应该采用这个协议:
@interface MyDelegate <NSWindowNotifications> // ... @end
然后再协议中执行方法。对于诸如@optional(就和大多数委托方法一样)在协议中声明的方法,你仍然需要在调用特殊方法之前检查-respondsToSelector:。 苹果建议这种方法,因为这个更精确,不会和NSObject弄混,并且提供更好的工具支持。
代替检查委托是否响应选择器,你可以在设置委托时存储相关信息。使用bitfield是一个非常清晰的方法,如下:
@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
然后,在正文里,可以通过访问delegateRespondsTo来检查委托处理邮件,而不是一遍又一遍的发送-respondsToSelector:。
上面的方法很厉害!但是如果你想在1分钟之内解决问题可以尝试一下这个: MyClass.h文件应该像这个样子(用评论添加委托行)
#import <BlaClass/BlaClass.h> @class MyClass; //定义类,这样协议可以看到MyClass @protocol MyClassDelegate //定义委托协议 - (void) myClassDelegateMethod: (MyClass *) sender; //定义在另一个类里实现的委托方法 @end //结束协议 @interface MyClass : NSObject { } @property (nonatomic, weak) id <MyClassDelegate> delegate; //定义 MyClassDelegate为委托 @end
MyClass.m 文件应该像这样:
#import "MyClass.h" @implementation MyClass @synthesize delegate; //综合MyClassDelegate 委托 - (void) myMethodToDoStuff { [self.delegate myClassDelegateMethod:self]; //这个会调用在其他类里实现的方法 } @end
为了在其他的类里使用委托(本情况是UIViewController调用MyVC)MyVC.h:
#import "MyClass.h" @interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate }
MyVC.m:
myClass.delegate = self; //设置委托至自身的某个地方
执行委托方法:
- (void) myClassDelegateMethod: (MyClass *) sender { NSLog(@"Delegates are great!"); }
当用正式的协议方法创建委托支持时,我发现可以确保正确的类型检查(虽然是运行时间,不是编译时间),通过添加如下代码:
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) { [NSException raise:@"MyDelegate Exception" format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__]; }
在你的委托访问(setDelegate)代码,这个能将错误最小化。
或许更多的是在于你所缺少的行。 如果从C++的视角来看,委托需要一点时间适应,但是基本上“他们只是工作”。 委托实现的方式是:设置NSWindow的委托对象,但是对象只为一个或几个可能的委托方法执行。所以会发生一些事,NSWindow想要调用对象,它只使用Objective-c的respondsToSelector方法来决定对象是否被调用,然后再调用。这就是objective-c的实现方式——根据需求寻找方法。 用你自己的对象实现这一点是非常琐碎的,没有什么特别的事情,你甚至可以为让一个实例有27个对象的NSArray,完全不同类型的对象,其中只有18个有-(void)setToBue;方法,其他的9个没有。所以在18个需要完成的调用setToBlue,就像这样:
for (id anObject in myArray) { if ([anObject respondsToSelector:@selector(@"setToBlue")]) [anObject setToBlue]; }
另外,委托是不保留的,所以需要在MyClass dealloc方法中将委托设置为nil。
请看下面的教程是如何一步一步介绍iOS中的委托的。
我创建了两个 ViewControllers (从一个给另一个发送) 1. FirstViewController 执行委托(提供数据). 2. SecondViewController声明委托(接收数据).
1. 来自@Jesse Rusak 的回答:
Objective-C 委托就是已被指定为另一个委托的对象,没有特殊的创建过程,你只要定义一个实现你感兴趣的委托方法的类就可以。(虽然委托使用正式协议,但你必须得声明委托来执行该协议,如下所示)
例如,假设你有个NSWindow。如果你想要实现他的委托的 windowDidMove: 方法,你可以创建一个这样的类:
然后创建一个MyClass的实例并制定为window的委托:
在NSWindow方面, 可能有类似于此的代码使用 respondsToSelector: 来看委托是否响应windowDidMove:信息,如何合适就发送。
委托资源本身是典型声明的weak(ARC)或assign(预ARC)来避免循环,因为对象委托经常持有强引用该对象(例如,一个视图控制器通常包含视图委托)
要定义自己的委托,你需要在某个地方声明方法。有两个基本的方法,苹果的文档协议有讨论过.
1) 一个非正式的协议
这个就和NSWindow差不多,在NSObject的类别实现。例如,继续上面的例子,这是从NSWindow.h:转述的:
就像上面描述的那样,当调用这个函数的时候,你会使用-respondsToSelector:,委托简单的实现此方法,就完成了。这个方法在苹果的库里是直接常见的,但是新的代码应该是用下面的更现代的方法。
2)一个正式的协议
新的选择是声明一个正式的协议。声明应该像这个样子:
这类似于一个借口或者抽象基类,因为这为委托建立了一个特殊的类型,这种情况下是NSWindowNotifications。委托执行者应该采用这个协议:
然后再协议中执行方法。对于诸如@optional(就和大多数委托方法一样)在协议中声明的方法,你仍然需要在调用特殊方法之前检查-respondsToSelector:。
苹果建议这种方法,因为这个更精确,不会和NSObject弄混,并且提供更好的工具支持。
优化速度
代替检查委托是否响应选择器,你可以在设置委托时存储相关信息。使用bitfield是一个非常清晰的方法,如下:
然后,在正文里,可以通过访问delegateRespondsTo来检查委托处理邮件,而不是一遍又一遍的发送-respondsToSelector:。
2. 来自@Tibidabo
上面的方法很厉害!但是如果你想在1分钟之内解决问题可以尝试一下这个:
MyClass.h文件应该像这个样子(用评论添加委托行)
MyClass.m 文件应该像这样:
为了在其他的类里使用委托(本情况是UIViewController调用MyVC)MyVC.h:
MyVC.m:
执行委托方法:
3. 来自@umop
当用正式的协议方法创建委托支持时,我发现可以确保正确的类型检查(虽然是运行时间,不是编译时间),通过添加如下代码:
在你的委托访问(setDelegate)代码,这个能将错误最小化。
4. 来自@Tom Andersen的回答
或许更多的是在于你所缺少的行。
如果从C++的视角来看,委托需要一点时间适应,但是基本上“他们只是工作”。
委托实现的方式是:设置NSWindow的委托对象,但是对象只为一个或几个可能的委托方法执行。所以会发生一些事,NSWindow想要调用对象,它只使用Objective-c的respondsToSelector方法来决定对象是否被调用,然后再调用。这就是objective-c的实现方式——根据需求寻找方法。
用你自己的对象实现这一点是非常琐碎的,没有什么特别的事情,你甚至可以为让一个实例有27个对象的NSArray,完全不同类型的对象,其中只有18个有-(void)setToBue;方法,其他的9个没有。所以在18个需要完成的调用setToBlue,就像这样:
另外,委托是不保留的,所以需要在MyClass dealloc方法中将委托设置为nil。
5. 来自@RDC 的回答:
请看下面的教程是如何一步一步介绍iOS中的委托的。
我创建了两个 ViewControllers (从一个给另一个发送)
1. FirstViewController 执行委托(提供数据).
2. SecondViewController声明委托(接收数据).