有没有办法在 Objective-C 中一次委托给两个对象?我知道委托模式意味着一次一个响应,并且对于多个听众和广播有通知中心,但通知不返回任何值。
如果我有一个基于网络的 iOS 项目并且需要委托给多个侦听器并需要从它们返回值,那么在这种情况下,哪种方法应该是最好的?
有没有办法在 Objective-C 中一次委托给两个对象?我知道委托模式意味着一次一个响应,并且对于多个听众和广播有通知中心,但通知不返回任何值。
如果我有一个基于网络的 iOS 项目并且需要委托给多个侦听器并需要从它们返回值,那么在这种情况下,哪种方法应该是最好的?
在每个班级中,代表都是一个,因此一个代表被告知该事件。但是没有什么禁止你声明一个带有一组委托的类。
或者改用观察。一个类可以被多个类观察。
例子
根据 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,因为如评论中所述,应使用弱指针来保存委托以避免保留循环。
除了Ramys 答案,您还可以使用 a[NSHashTable weakObjectsHashTable]
而不是 a
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
如果您正在编写将调用委托的函数,您可以拥有任意数量的委托。但是,如果您正在使用调用委托的类(您无法更改),那么您的委托不能超过该类支持的数量。
如果对您有用,您可以让一位代表给另一位代表打电话。设置第一个委托,以便它调用第二个委托(其指针存储在第一个委托对象中)。这可以很简单,使用 Objective-C 的动态调用机制预先定义“传递”哪些调用,或者相当复杂。
Robbie Hanson 编写了一个多播委托实现。看起来像你需要的。他在这里更详细地讨论了它,以及它是如何在 XMPPFramework 中使用的。他对主要问题之一进行了很好的讨论,即如何处理多个委托实现给定方法的情况,该方法的返回值决定了类的行为(并且多个委托返回不同的值)。相关位:
什么是 MulticastDelegate?
xmpp 框架需要支持无限数量的扩展。这包括框架附带的官方扩展,以及您可能想要插入框架的任意数量的扩展或自定义代码。所以传统的委托模式根本行不通。XMPP 模块和扩展需要分离到它们自己独立的类中,但是这些类中的每一个都需要接收委托方法。而且标准的 NSNotification 架构也不起作用,因为其中一些委托需要返回变量。(另外,从通知的 userInfo 字典中提取参数真的很烦人。)
因此,MulticastDelegate 允许您使用标准委托范例插入框架,但它允许多个类接收相同的委托通知。这样做的好处是您不必将所有 xmpp 处理代码放在一个类中。你可以将你的处理分成多个类,或者你认为合适的。
一个委托只能为一个对象设置,但可以将委托存储在数组中。Ramy Al Zuhouri 的变体很好,但我想说从数组中释放委托可能是一个问题,因为 NSArray(如 NSMutableArray)类保留所有添加的对象,但委托在大多数情况下是一个没有 retainCount 的分配属性。保留委托可能会导致具有委托实现的类将具有 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
如果你想为类B
和只有一个委托的类调用回调,你可以创建一个委托包装器C
,它具有对类的引用和. 然后类调用回调 on和through 。A
DWrap
B
C
A
B
C
DWrap