10

この質問に関連して、バックグラウンド スレッドからメイン スレッドに作業をディスパッチするために GCD を使用するのに対して、メイン スレッドでオブザーバーを使用して NSNotification をいつ使用するかに関して、一般的に受け入れられているロジックがあるかどうか疑問に思っていました。

通知オブザーバーのセットアップでは、ビューがアンロードされたときにオブザーバーを破棄することを覚えておく必要があるようですが、その後、通知を確実に無視します。ジョブをメインスレッドにディスパッチすると、ビューが実行されたときにブロックが実行される可能性がありますアンロードされました。

そのため、通知によってアプリの安定性が向上するはずだと私には思えます。私が GCD について読んだことから、ディスパッチ オプションがより良いパフォーマンスを提供すると思いますか?

アップデート:

通知とディスパッチは一緒にうまく機能し、場合によっては一緒に使用する必要があることを認識しています。使用すべき/すべきでない特定のケースがあるかどうかを調べようとしています。

例: メイン キューで受信関数を単にディスパッチするのではなく、ディスパッチされたブロックから通知を発生させるメイン スレッドを選択するのはなぜですか? (明らかに、この 2 つのケースでは、受信機能にいくつかの変更が加えられますが、最終的な結果は同じように見えます)。

4

1 に答える 1

14

NSNotificationCentergcd&はdispatch_get_main_queue()非常に異なる目的を果たします。「vs」が本当に当てはまるとは思いません。

NSNotificationCenterアプリケーションの異なる部分を分離する方法を提供します。たとえばkReachabilityChangedNotification、Apple の Reachability サンプル コードは、システム ネットワークの状態が変化したときに通知センターに投稿されます。次に、通知センターにセレクター/呼び出しを呼び出すように依頼して、そのようなイベントに応答できるようにすることができます (空襲のサイレンを考えてください)。

gcd一方、指定したキューで実行する作業をすばやく割り当てる方法を提供します。マルチスレッドとマルチコア CPU を利用するために、コードを分析して個別に処理できるポイントをシステムに伝えることができます。

通常 (ほとんどの場合)、通知は投稿されたスレッドで確認されます。APIの1つの部分の注目すべき例外を除いて...

これらの概念が交差する 1 つの 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...
    });
}

もちろん、この例ではバックグラウンド スレッドに通知を投稿することはできませんが、どのスレッドに通知を投稿するかについて保証のないフレームワークを使用している場合に便利です。

于 2012-11-21T00:24:10.977 に答える