Objective c 单例对象的委托

Objective c 单例对象的委托,objective-c,ios,cocoa-touch,Objective C,Ios,Cocoa Touch,我有一个NSObject,它是一个singleton。这个单例类是否存在委托问题?我担心对于单例类型来说它会失败 这是我的设想。我有一个函数(在这个单例类中),它执行异步请求,从API中提取NSDictionary。基本上,当这个请求完成时,我想通知一个类请求已经完成最健壮的顺序排列) 保持简单 将你的应用程序设计为永远不要让多个对象同时成为singleton的代理(这可能是不可能的) NSNotification 使用NSNotificationCenter发出事件信号,而不是委派。请参阅此帖

我有一个NSObject,它是一个singleton。这个单例类是否存在委托问题?我担心对于单例类型来说它会失败


这是我的设想。我有一个函数(在这个单例类中),它执行异步请求,从API中提取NSDictionary。基本上,当这个请求完成时,我想通知一个类请求已经完成
您基本上有三种选择:

  • 使用委托。singelton是一个对象,因此它当然可以有一个委托。如果有多个对象需要使用它,并且需要将自己设置为代理,则每次都可以重置它们,但这可能会有问题

  • 使用通知,如Richard J.Ross III所示,但严肃地说:我觉得很奇怪,如果你是单身,需要通知一位代表,但你会使用广播技术

  • 使用完成块,其中调用对象将一个块传递给singleton,一旦singleton完成任务,该块就会被执行。请参阅(好的,这不是一个单例,而是一个类方法。原理相同),它使用一个完成块,或者使用一个成功块和一个失败块的great。
    根据其示例代码:

    [[AFGowallaAPIClient sharedClient] getPath:urlString 
                                    parameters:mutableParameters 
                                       success:^(__unused AFHTTPRequestOperation 
                                                 *operation, 
                                                 id JSON) 
        {
            NSMutableArray *mutableRecords = [NSMutableArray array];
            for (NSDictionary *attributes in [JSON valueForKeyPath:@"spots"]) {
                Spot *spot = [[[Spot alloc] initWithAttributes:attributes] autorelease];
                [mutableRecords addObject:spot];
            }
    
            if (block) {
                block([NSArray arrayWithArray:mutableRecords]);
            }
        } failure:^(__unused AFHTTPRequestOperation *operation, NSError *error) {
            if (block) {
                block([NSArray array]);
            }
    }];
    

单例委托没有错,但它确实会创建许多需要处理的边缘情况。例如:

  • 如果对象A调用setDelegate:,紧接着对象B调用setDelegate:,则对象A将永远不会收到委托调用

  • 在取消设置singleton的委托之前,需要检查您是否是委托人。通常在
    dealloc
    中调用
    singleton.delegate=nil。若另一个对象恰好在您之后成为委托,那个么您只是让它们意外地停止成为委托

有代表的单身人士并不是一种成熟的模式。根据用例的健壮程度,您的解决方案应该有所不同。以下是一些解决方案(按最简单->最健壮的顺序排列)

保持简单

将你的应用程序设计为永远不要让多个对象同时成为singleton的代理(这可能是不可能的)

NSNotification

使用NSNotificationCenter发出事件信号,而不是委派。请参阅此帖子中发布的其他一些答案

多个代表

扩展单例以支持多个委托。将
setDelegate:
替换为:
addDelegate:
removeDelegate:

@property (atomic) NSMutableArray *delegates;

- (void)addDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates addObject:foo];
}
- (void)removeDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates removeObject:foo];
}
- (void)signalDelegateEvent {
    [self.delegates enumerateObjectsUsingBlock:^(id<YourProtocol> obj,
                                                 NSUInteger idx,
                                                 BOOL *stop) {
        // call delegate method `foo` on each delegate
        if ( [obj respondsToSelector:@selector(foo)]) {
            [obj foo];
        } 
    }];
}
@property(原子)NSMutableArray*委托;
-(void)addDelegate:(NSObject*)foo{
[self.addObject:foo];
}
-(void)removeDelegate:(NSObject*)foo{
[self.delegates-removeObject:foo];
}
-(无效)signalDelegateEvent{
[self.delegates枚举对象使用块:^(id对象,
整数idx,
BOOL*停止){
//对每个委托调用委托方法'foo'
if([obj respondsToSelector:@selector(foo)]){
[obj foo];
} 
}];
}

我已经在许多应用程序中成功地使用了多代理模式。如果选择这种方法,请仔细考虑多线程是如何影响事情的。

为什么代理会失败?对于多个侦听器,您可以考虑使用<代码> NSNotificationCenter < /代码>。我只有一个类要通知,也更新了问题上下文。above@adit如果您迫切需要加快观察者查找速度,您可以在单例中使用一个特殊的
NSNotificationCenter
。在这种情况下,只需将其设置为singleton的只读属性,以便观测者可以直接向其注册。这确实是一种糟糕的形式。为什么有人会故意这样修改代码?请参阅vikingosegundo的答案,了解两个更好的解决方案,其中包括一名代表或blocks@PostCodeism我不太明白。我的代码有什么问题?您将如何使用NSNotificationCenter?@RichardJ.RossIII抱歉,这是一种过度反应。具体来说,您的代码没有问题,我更喜欢谈论NSNotifications。只是NSNotifications被过度使用是因为它们很简单,但它们很难通过代码进行跟踪。总的来说,对于iOS中的单例,块将是更好的解决方案。@PostCodeism no,而不是多播解决方案。它们都是用于不同场景的工具,显然没有通用的解决方案。我从未想过使用多代理解决方案,谢谢你的想法。很高兴在头脑中有一个委托模式的变体。如何使用一个必需的回调来通知委托对象它们即将被替换?此解决方案可以使用NSSet而不是NSArray来收集委托,以确保没有任何内容接收到多条消息。亲爱的审阅者:编辑一篇文章来修复打字错误是可以的,非常感谢。但添加到我甚至不知道的库的链接不是。
@property (atomic) NSMutableArray *delegates;

- (void)addDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates addObject:foo];
}
- (void)removeDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates removeObject:foo];
}
- (void)signalDelegateEvent {
    [self.delegates enumerateObjectsUsingBlock:^(id<YourProtocol> obj,
                                                 NSUInteger idx,
                                                 BOOL *stop) {
        // call delegate method `foo` on each delegate
        if ( [obj respondsToSelector:@selector(foo)]) {
            [obj foo];
        } 
    }];
}