Сравнение GCD и executeSelectorInBackground: dispatch_async не в фоновом режиме - PullRequest
6 голосов
/ 01 апреля 2011

Grand Central Dispatch великолепен и уменьшает объем кода, но почему я не могу запустить что-то в фоновом потоке?
Я сделал пример приложения, чтобы показать, что я имею в виду (ни одна из прокомментированных работ):

- (IBAction)performSel {
    [self performSelectorInBackground:@selector(doStuff) withObject:nil];
    [NSThread sleepForTimeInterval:3];
    [[self.view.subviews lastObject] removeFromSuperview];
}

- (IBAction)gcd {
    dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
    //dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    //dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    //dispatch_async(dispatch_get_main_queue(), ^(void) {
    //dispatch_sync(dispatch_get_main_queue(), ^(void) {
        [self doStuff]; // only for readability, will move the code on success
    });
    [NSThread sleepForTimeInterval:3];
    [[self.view.subviews lastObject] removeFromSuperview];
}

- (void)doStuff {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

    UIView *abortingView = [[UIView alloc]initWithFrame: self.view.bounds];
    abortingView.backgroundColor = [UIColor whiteColor];
    abortingView.alpha = 0.7;
    [self.view insertSubview:abortingView atIndex:10];
    [abortingView release];

    [pool drain];
}

[NSThread sleepForTimeInterval:3]; для имитации функциональности пользовательского интерфейса по умолчанию. Например, если кто-то переключается с одного вида навигации на другой.
Просто скопируйте код в новое приложение на основе представления, создайте две кнопки и соедините их.

1 Ответ

24 голосов
/ 07 апреля 2011

UIKit классы должны использоваться только из основного потока приложения. (Начиная с iOS4, рисование в графическом контексте является поточно-ориентированным.) Вы не можете использовать UIKit в фоновом потоке.

Таким образом, вы можете использовать dispatch_async (dispatch_get_main_queue (), block) только в этой ситуации.

dispatch_async(dispatch_get_main_queue(), ^(void) {

Он вызовет блок в главном потоке в цикле выполнения основного потока.

dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

Это вызовет блок в фоновом потоке. Вы не можете использовать его, потому что вы хотите использовать UIKit в блоке. И будьте осторожны dispatch_async (dispatch_queue_create (, это может вызвать утечку памяти, вам нужно освободить последовательную очередь, созданную dispatch_queue_create.

dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

dispatch_sync ждет, пока блок не будет завершен.

dispatch_sync(dispatch_get_main_queue(), ^(void) {

Это вызывает DEADLOCK.

...