有没有办法在Objective-C中一次委托两个对象?我知道委托模式一次意味着一个响应,并且对于多个听众和广播有通知中心但是通知不会返回任何值。
如果我有一个基于网络的大量iOS项目并且需要委托多个侦听器并且需要从它们返回值,那么在这种情况下哪种方法应该是最好的?
答案 0 :(得分:32)
在每个班级中,代表都是一名,因此一名代表会被告知该事件。但是没有什么禁止你用一组委托声明一个类。
或者改用观察。可以通过多个类来观察类。
示例
根据OP的要求,因为一些代码也很有用,这是一种方法:
@interface YourClass()
@property (nonatomic, strong, readwrite) NSPointerArray* delegates;
// The user of the class shouldn't even know about this array
// It has to be initialized with the NSPointerFunctionsWeakMemory option so it doesn't retain objects
@end
@implementation YourClass
@synthesize delegates;
... // other methods, make sure to initialize the delegates set with alloc-initWithOptions:NSPointerFunctionsWeakMemory
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
[delegates addPointer: delegate];
}
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Remove the pointer from the array
for(int i=0; i<delegates.count; i++) {
if(delegate == [delegates pointerAtIndex: i]) {
[delegates removePointerAtIndex: i];
break;
}
} // You may want to modify this code to throw an exception if no object is found inside the delegates array
}
@end
这是一个非常简单的版本,你可以用另一种方式完成。我不建议公开委托设置,你永远不知道如何使用它,你可以得到一个不一致的状态,特别是多线程。此外,当您添加/删除委托时,您可能需要运行其他代码,这就是为什么将委托设置为私有。
您可能还有许多其他方法,例如delegatesCount
。
PS:代码已被编辑为 NSPointerArray 而不是 NSMutableSet ,因为如评论中所述,委托应该使用弱指针来避免保留周期。
答案 1 :(得分:20)
除Ramys answer外,您还可以使用[NSHashTable weakObjectsHashTable]
代替。NSMutableSet
@property (nonatomic, weak) id delegate;
。这将只保留对您的委托的弱引用,并防止您遇到内存泄漏。
您将从标准弱代理@interface YourClass()
@property (nonatomic, strong) NSHashTable *delegates;
@end
@implementation YourClass
- (instancetype)init
{
self = [super init];
if (self) {
_delegates = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void) addDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates addObject: delegate];
}
// calling this method is optional, because the hash table will automatically remove the delegate when it gets released
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
{
// Additional code
[_delegates removeObject: delegate];
}
@end
{{1}}
答案 2 :(得分:4)
一个委托只能设置一个对象,但可以将代理存储在数组中。 Ramy Al Zuhouri的变体很好,但我想说从数组中释放委托可能是一个问题,因为NSArray(如NSMutableArray)类保留所有添加的对象,但在大多数情况下委托是一个不带retainCount的assign属性。保留委托可能会导致具有委托实现的类具有retainCount + 1。 解决方法是在NSMutableArray中存储委托,就像指向委托方法的指针一样。 我正在使用带有委托标题的单一类。
//YourClass.h file
@protocol YourDelegateProtocol <NSObject>
-(void)delegateMethod;
@end
@interface YourClass : NSObject
+(YourClass *)sharedYourClass;
- (void) addDelegate: (id<YourDelegateProtocol>) delegate;
- (void) removeDelegate: (id<YourDelegateProtocol>) delegate
@end
//YourClass.m file
@interface YourClass()
@property (nonatomic, retain) NSMutableArray *delegates;
-(void)runAllDelegates;
@end
@implementation YourClass
@synthesize delegates = _delegates;
static YourClass *sharedYourClass = nil;
+(YourClass *)sharedYourClass {
if (!sharedYourClass || sharedYourClass == nil) {
sharedYourClass = [YourClass new];
sharedYourClass.delegates = [NSMutableArray array];
}
return sharedYourClass;
}
-(void)addDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates addObject: pointerToDelegate];
}
-(void)removeDelegate: (id<YourDelegateProtocol>) delegate{
NSValue *pointerToDelegate = [NSValue valueWithPointer:delegate];
[_delegates removeObject: pointerToDelegate];
}
-(void)runAllDelegates{
//this method will run all delegates in array
for(NSValue *val in sharedYourClass.delegates){
id<YourDelegateProtocol> delegate = [val pointerValue];
[delegate delegateMethod];
}
}
-(void)dealloc{
sharedYourClass.delegates =nil;
[sharedYourClass release], sharedYourClass =nil;
[super dealloc];
}
@end
//YourClassWithDelegateImplementation.h file
#include "YourClass.h"
@interface YourClassWithDelegateImplementation : NSObject <YourDelegateProtocol>
@end
//YourClassWithDelegateImplementation.m file
@implementation YourClassWithDelegateImplementation
-(id)init{
self = [super init];
if(self){
//...your initialization code
[[YourClass sharedYourClass] addDelegate:self];
}
return self;
}
-(void)delegateMethod{
//implementation of delegate
}
-(void)dealloc{
[[YourClass sharedYourClass] removeDelegate:self];
[super dealloc];
}
@end
答案 3 :(得分:3)
如果您正在编写将调用代理人的功能,您可以拥有任意数量的代理。但是如果你正在使用一个调用委托的类(你不能改变),那么你就不能拥有比类支持更多的委托。
如果有效,你可以让一个代表打电话给另一个。设置第一个委托,以便它将调用第二个委托(其指针存储在第一个委托对象中)。这可以很简单,使用Objective-C的动态调用机制预先定义哪些调用“传递”或相当复杂。
答案 4 :(得分:3)
Robbie Hanson写了multicast delegate implementation。看起来像你需要的。他更详细地讨论了here,以及如何在XMPPFramework中使用它。他对一个主要问题有一些很好的讨论,即如何处理多个委托实现给定方法的情况,其中返回值确定类的行为(并且多个委托返回不同的值)。相关位:
什么是MulticastDelegate?
xmpp框架需要支持无限数量的扩展。 这包括框架附带的官方扩展,如 以及您可能想要插入的任意数量的扩展或自定义代码 进入框架。所以传统的委托模式根本不会 工作。 XMPP模块和扩展需要分离成自己的模块和扩展 单独的类,但这些类中的每一个都需要接收委托 方法。标准的NSNotification架构不起作用 或者因为其中一些委托需要返回变量。 (另外,从通知中提取参数真的太烦人了 userInfo字典。)
所以MulticastDelegate允许你使用the插入框架 标准委托范例,但它允许多个类接收 相同的代表通知。这样做的好处就是你没有 必须将所有xmpp处理代码放在一个类中。您可以 将您的处理分成多个类,或者您认为合适。
答案 5 :(得分:1)
如果要从只有一个委托的类B
调用类C
和A
的回调,可以创建一个委托包装器DWrap
,其中包含一个课程B
和C
。然后,课程A
会通过B
调用C
和DWrap
上的回调。