Ответ 1
NSNotificationCenter
и gcd
и dispatch_get_main_queue()
служат для разных целей. Я не знаю, что "против" действительно применимо.
NSNotificationCenter
обеспечивает способ устранения разрозненных частей вашего приложения. Например, пример кода kReachabilityChangedNotification
в Apple Reachability отправляется в центр уведомлений при изменении состояния сетевой системы. И, в свою очередь, вы можете попросить центр уведомлений вызвать ваш селектор/вызов, чтобы вы могли ответить на такое событие. (Think Air Raid Siren)
gcd
, с другой стороны, обеспечивает быстрый способ задания работы в указанной вами очереди. Он позволяет вам рассказать системе о точках, в которых ваш код может быть расчленен и обработан отдельно, чтобы использовать преимущества нескольких потоков и многоядерных процессоров.
Обычно (почти всегда) уведомления отображаются в потоке, на котором они размещаются. За исключением одного фрагмента 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...
});
}
Конечно, в этом примере вы можете просто не размещать уведомление в фоновом потоке, но это может пригодиться, если вы используете фреймворк, который не дает никаких гарантий относительно того, в какой поток он будет отправлять уведомления.