Подтвердить что ты не робот

Block_release освобождение объектов пользовательского интерфейса в фоновом потоке

Один из шаблонов, представленных на конференции WWDC 2010 "Блоки и грандиозная центральная диспетчерская связь", заключался в использовании вложенных вызовов dispatch_async для выполнения трудоемких задач в фоновом потоке и затем обновления пользовательского интерфейса в основном потоке после завершения задачи

dispatch_async(backgroundQueue, ^{
    // do something time consuming in background
    NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();

    // use results on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        [myViewController UpdateUiWithResults:results];
    });
});

Так как "myViewController" используется внутри блоков, он автоматически получает "сохранить" и позже получит "release", когда блоки будут очищены.

Если вызов блока "release" является окончательным вызовом освобождения (например, пользователь перемещается в сторону от представления во время выполнения фоновой задачи) вызывается метод dealloc myViewController, но он вызывает фоновый поток!

Объекты UIKit не любят быть выделенными вне основного потока. В моем случае UIWebView выдает исключение.

Как этот WWDC может представить шаблон, который конкретно упоминается как лучший новый способ избежать блокировки пользовательского интерфейса - быть настолько ошибочным? Я что-то упускаю?

4b9b3361

Ответ 1

Вы можете использовать квалификатор типа __block для такого случая. __block переменные автоматически не сохраняются блоком. Поэтому вам нужно сохранить объект самостоятельно:

__block UIViewController *viewController = [myViewController retain];
dispatch_async(backgroundQueue, ^{
    // Do long-running work here.
    dispatch_async(dispatch_get_main_queue(), ^{
        [viewController updateUIWithResults:results];
        [viewController release]; // Ensure it released on main thread
    }
});

ИЗМЕНИТЬ

С ARC объект переменной __block автоматически сохраняется блоком, но мы можем установить значение nil переменной __block для отпускания сохраненного объекта всякий раз, когда мы хотим.

__block UIViewController *viewController = myViewController;
dispatch_async(backgroundQueue, ^{
    // Do long-running work here.
    dispatch_async(dispatch_get_main_queue(), ^{
        [viewController updateUIWithResults:results];
        viewController = nil; // Ensure it released on main thread
    }
});

Ответ 2

В потоке я просто использую [viewController retain];, а затем в конце использования потока [viewController release]. Он работает, и я не использую GCD~

Ответ 3

Это сработало для меня (добавлен таймер):

[self retain]; // this guarantees that the last release will be on the main threaad
dispatch_async(backgroundQueue, ^{
    // do something time consuming in background
    NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();

    // use results on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        [myViewController UpdateUiWithResults:results];
        [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(releaseMe:) userInfo:nil repeats:NO];
    });
});
- (void)releaseMe:(NSTimer *)theTimer {
    [self release]; // will be on the main thread
}