Почему UIViewController освобождается в основном потоке?

Я недавно наткнулся наПроблема распределения в некотором коде Objective-C. Эта тема обсуждалась ранее при переполнении стека вBlock_release освобождает объекты пользовательского интерфейса в фоновом потоке, Я думаю, что понимаю проблему и ее последствия, но, конечно, я хотел воспроизвести ее в небольшом тестовом проекте. Я сначала создал свой собственныйSOUnsafeObject (= объект, который всегда должен быть освобожден в основном потоке).

@interface SOUnsafeObject : NSObject

@property (strong) NSString *title;

- (void)reloadDataInBackground;

@end


@implementation SOUnsafeObject

- (void)reloadDataInBackground {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            self.title = @"Retrieved data";
        });

        sleep(3);
    });
}

- (void)dealloc {
    NSAssert([NSThread isMainThread], @"Object should always be deallocated on the main thread");
}

@end}]

Теперь, как и ожидалось, если я поставлю[[[SOUnsafeObject alloc] init] reloadDataInBackground]; внутриapplication:didFinishLaunching.. приложение вылетает через 3 секунды из-за ошибочного подтверждения. Предлагаемое исправление, похоже, работает. То есть приложение больше не падает, если я изменю реализациюreloadDataInBackground чтобы:

__block SOUnsafeObject *safeSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        safeSelf.title = @"Retrieved data";
        safeSelf = nil;
    });

    sleep(3);
});

Итак, похоже, что мое понимание проблемы и того, как ее можно решить в рамках ARC, является правильным. Но просто чтобы быть на 100% уверенным .. Давайте попробуем то же самое сUIViewController (так какUIViewController вероятно, будет выполнять рольSOUnsafeObject в реальной жизни). Реализация практически идентичнаSOUnsafeObject:

@interface SODemoViewController : UIViewController

- (void)reloadDataInBackground;

@end


@implementation SODemoViewController

- (void)reloadDataInBackground {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            self.title = @"Retrieved data";
        });

        sleep(3);
    });
}

- (void)dealloc {
    NSAssert([NSThread isMainThread], @"UI objects should always be deallocated on the main thread");
    NSLog(@"I'm deallocated!");
}

@end

Теперь давайте[[SODemoViewController alloc] init] reloadDataInBackground]; внутриapplication:didFinishLaunching.., Хм, утверждение не ошибается .. СообщениеI'm deallocated! выводится на консоль через 3 секунды, поэтому я почти уверен, что контроллер представления освобождается.

Почему контроллер представления освобождается в основном потоке, а небезопасный объект освобождается в фоновом потоке? Код практически идентичен. Есть лиUIKit делать какие-то модные вещи за кулисами, чтобы убедиться,UIViewController всегда освобождается в основном потоке? Я начинаю подозревать это, так как следующий фрагмент также не нарушает мое утверждение:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    SODemoViewController()
});

Если да, документировано ли это поведение где-нибудь? Можно ли полагаться на это поведение? Или я просто совершенно не прав и есть что-то очевидное, что я здесь упускаю?

Заметки: Я полностью осознаю тот факт, что я могу использовать__weak ссылка здесь, но давайте предположим, что контроллер представления все еще должен быть жив, чтобы выполнить наш код завершения в главном потоке. Кроме того, я пытаюсь понять суть проблемы, прежде чем обойти ее. Я преобразовал код в Swift и получил те же результаты, что и в Objective-C (исправление дляSOUnsafeObject там синтаксически еще страшнее).

Ответы на вопрос(1)

Ваш ответ на вопрос