¿Por qué se desasigna UIViewController en el hilo principal?

Recientemente me topéEl problema de desasignación en algún código Objective-C. Este tema se discutió antes en Stack Overflow enBlock_release desasignando objetos UI en un hilo de fondo. Creo que entiendo el problema y sus implicaciones, pero para estar seguro, quería reproducirlo en un pequeño proyecto de prueba. Primero creé el míoSOUnsafeObject (= un objeto que siempre debe ser desasignado en el hilo principal).

@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}]

Ahora, como se esperaba, si pongo[[[SOUnsafeObject alloc] init] reloadDataInBackground]; dentroapplication:didFinishLaunching.. la aplicación se bloquea después de 3 segundos debido a la afirmación fallida. La solución propuesta parece funcionar. Es decir. la aplicación ya no se bloquea si cambio la implementación dereloadDataInBackground a:

__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);
});

De acuerdo, parece que mi comprensión sobre el problema y cómo se puede resolver con ARC es correcta. Pero solo para estar 100% seguro ... Probemos lo mismo con unUIViewController (desde unUIViewController probablemente cumplirá el papel deSOUnsafeObject en la vida real). La implementación es casi idéntica a la delSOUnsafeObject:

@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

Ahora pongamos[[SODemoViewController alloc] init] reloadDataInBackground]; dentroapplication:didFinishLaunching... Hmm, la afirmación no falla ... El mensajeI'm deallocated! se imprime en la consola después de 3 segundos, así que estoy bastante seguro de que el controlador de vista se desasigna.

¿Por qué se desasigna el controlador de vista en el hilo principal mientras que el objeto inseguro se desasigna en un hilo de fondo? El código es casi idéntico. HaceUIKit hacer algunas cosas elegantes detrás de escena para asegurarse de queUIViewController siempre se desasigna en el hilo principal? Estoy empezando a sospechar esto ya que el siguiente fragmento tampoco rompe mi afirmación:

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

Si es así, ¿se documenta este comportamiento en alguna parte? ¿Se puede confiar en este comportamiento? ¿O simplemente estoy totalmente equivocado y hay algo obvio que me estoy perdiendo aquí?

Notas: Soy plenamente consciente del hecho de que puedo usar un__weak haga referencia aquí, pero supongamos que el controlador de vista aún debería estar activo para ejecutar nuestro código de finalización en el hilo principal. Además, estoy tratando de entender el núcleo del problema aquí antes de evitarlo. Convertí el código a Swift y obtuve los mismos resultados que en Objective-C (la solución paraSOUnsafeObject ¿existe sintácticamente aún más feo).

Respuestas a la pregunta(1)

Su respuesta a la pregunta