NSNotification与dispatch_get_main_queue

时间:2012-11-20 20:39:45

标签: ios grand-central-dispatch nsnotifications

关于this question我想知道是否有任何普遍接受的逻辑关于何时使用NSNotification,在主线程中使用观察者,使用GCD将工作从后台线程调度到主线程?

似乎通过通知 - 观察者设置,您必须记住在视图卸载时拆除观察者,然后您可靠地忽略通知,其中将作业分派给主线程可能导致块被执行时视图已被卸载。

因此,在我看来,通知应该提供更好的应用稳定性。我假设调度选项提供了比我读过的GCD更好的性能吗?

更新

我知道通知和发送可以一起愉快地工作,在某些情况下,应该一起使用。我试图找出是否存在应该/不应该使用的特定情况。

示例案例:为什么我会选择主线程来从调度块中发出通知,而不是仅仅调度主队列上的接收函数? (显然在这两种情况下接收功能会有一些变化,但最终结果似乎是相同的)。

1 个答案:

答案 0 :(得分:14)

NSNotificationCentergcd& dispatch_get_main_queue()用于非常不同的目的。我不认为“vs”是真正适用的。

NSNotificationCenter提供了一种解耦应用程序中不同部分的方法。例如,当系统网络状态发生变化时,Apple的Reachability示例代码中的kReachabilityChangedNotification将发布到通知中心。反过来,您可以要求通知中心调用您的选择器/调用,以便您可以响应此类事件。(Think Air Raid Siren)

另一方面,

gcd提供了一种快速方法,可以在您指定的队列上分配要完成的工作。它允许您告诉系统可以分别解析和处理代码的点,以利用多线程和多核CPU。

通常(几乎总是)在发布它们的线程上观察通知。除了一个API之外......

这些与概念相交的API是NSNotificationCenter的:

addObserverForName:object:queue:usingBlock:

这实际上是一种确保在给定线程上观察到给定通知的方便方法。虽然“usingBlock”参数会在幕后使用gcd

以下是其用法示例。假设我的代码中某处有NSTimer每秒调用此方法:

-(void)timerTimedOut:(NSTimer *)timer{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // Ha! Gotcha this is on a background thread.
        [[NSNotificationCenter defaultCenter] postNotificationName:backgroundColorIsGettingBoringNotification object:nil];
    });
}

我想使用backgroundColorIsGettingBoringNotification作为信号来改变视图控制器视图的背景颜色。但是它发布在后台线程上。好吧,我可以使用前面提到的API来观察只在主线程上。请注意以下代码中的viewDidLoad

@implementation NoWayWillMyBackgroundBeBoringViewController {
    id _observer;
}
-(void)observeHeyNotification:(NSNotification *)note{
    static NSArray *rainbow = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        rainbow = @[[UIColor redColor], [UIColor orangeColor], [UIColor yellowColor], [UIColor greenColor], [UIColor blueColor], [UIColor purpleColor]];
    });
    NSInteger colorIndex = [rainbow indexOfObject:self.view.backgroundColor];
    colorIndex++;
    if (colorIndex == rainbow.count) colorIndex = 0;
    self.view.backgroundColor = [rainbow objectAtIndex:colorIndex];
}
- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    __weak PNE_ViewController *weakSelf = self;
    _observer = [[NSNotificationCenter defaultCenter] addObserverForName:backgroundColorIsGettingBoringNotification
                                                                  object:nil
                                                                   queue:[NSOperationQueue mainQueue]
                                                              usingBlock:^(NSNotification *note){
                                                                  [weakSelf observeHeyNotification:note];
                                                              }];
}
-(void)viewDidUnload{
    [super viewDidUnload];
    [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}
-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end

此API的主要优点似乎是在postNotification...调用期间将调用您的观察块。如果您使用标准API并按照以下方式实施observeHeyNotification:,则无法保证在执行调度块之前需要多长时间:

-(void)observeHeyNotification:(NSNotification *)note{
    dispatch_async(dispatch_get_main_queue(), ^{
        // Same stuff here...
    });
}

当然,在这个例子中你可能根本就不在背景线程上发布通知,但是如果你使用的框架不能保证它会在哪个线程上发布通知,这可能会派上用场。