委派给多个对象

时间:2013-01-11 13:07:10

标签: objective-c

有没有办法在Objective-C中一次委托两个对象?我知道委托模式一次意味着一个响应,并且对于多个听众和广播有通知中心但是通知不会返回任何值。

如果我有一个基于网络的大量iOS项目并且需要委托多个侦听器并且需要从它们返回值,那么在这种情况下哪种方法应该是最好的?

6 个答案:

答案 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调用类CA的回调,可以创建一个委托包装器DWrap,其中包含一个课程BC。然后,课程A会通过B调用CDWrap上的回调。