29

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

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

4

6 回答 6

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,因为如评论中所述,应使用弱指针来保存委托以避免保留循环。

于 2013-01-11T13:22:12.507 回答
20

除了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
于 2014-05-15T07:08:04.970 回答
3

如果您正在编写将调用委托的函数,您可以拥有任意数量的委托。但是,如果您正在使用调用委托的类(您无法更改),那么您的委托不能超过该类支持的数量。

如果对您有用,您可以让一位代表给另一位代表打电话。设置第一个委托,以便它调用第二个委托(其指针存储在第一个委托对象中)。这可以很简单,使用 Objective-C 的动态调用机制预先定义“传递”哪些调用,或者相当复杂。

于 2013-01-11T13:23:01.570 回答
3

Robbie Hanson 编写了一个多播委托实现。看起来像你需要的。他在这里更详细地讨论了它,以及它是如何在 XMPPFramework 中使用的。他对主要问题之一进行了很好的讨论,即如何处理多个委托实现给定方法的情况,该方法的返回值决定了类的行为(并且多个委托返回不同的值)。相关位:

什么是 MulticastDelegate?

xmpp 框架需要支持无限数量的扩展。这包括框架附带的官方扩展,以及您可能想要插入框架的任意数量的扩展或自定义代码。所以传统的委托模式根本行不通。XMPP 模块和扩展需要分离到它们自己独立的类中,但是这些类中的每一个都需要接收委托方法。而且标准的 NSNotification 架构也不起作用,因为其中一些委托需要返回变量。(另外,从通知的 userInfo 字典中提取参数真的很烦人。)

因此,MulticastDelegate 允许您使用标准委托范例插入框架,但它允许多个类接收相同的委托通知。这样做的好处是您不必将所有 xmpp 处理代码放在一个类中。你可以将你的处理分成多个类,或者你认为合适的。

于 2013-01-11T14:11:58.720 回答
3

一个委托只能为一个对象设置,但可以将委托存储在数组中。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
于 2013-02-22T09:43:51.000 回答
1

如果你想为类B和只有一个委托的类调用回调,你可以创建一个委托包装器C,它具有对类的引用和. 然后类调用回调 on和through 。ADWrapBCABCDWrap

于 2013-01-11T13:37:50.253 回答