ARC y autorelease

se utiliza la function de autorización automática para el object de function devuelto, por lo que la persona que llama no se apropiará y el destinatario liberará el object en el futuro.

Sin embargo, ARC es capaz de contar la propiedad de la persona que llama y liberarla después del uso, es decir, puede comportarse como Smart Pointer en C ++. Con ARC, puede deshacerse de autorelease porque autorelease no es determinista.

La razón por la que solicito esta pregunta es que veo las llamadas de object devuelto dealloc antes en ARC que el código no ARC. Esto me lleva a pensar que ARC puede comportarse como Smart Pointer y puede inutilizar el autoelemento. ¿Es verdad o posible? Lo único que puedo pensar sobre la utilidad de autorelease está en multiprocess o código de networking porque no puede ser más fácil contar la propiedad cuando el object está pasando.

Gracias por tus pensamientos.

Aquí hay una nueva edición para dejar en claro:

con autorelease

+ (MyClass*) myClass { return [[[MyCClass alloc] init] autorelease]; } - doSomething { MyClass *obj = [MyClass myClass]; } 

Con ARC:

 + (MyClass*) myClass { return [[MyCClass alloc] init]; // no autorelease } - doSomething { MyClass *obj = [MyClass myClass]; // insert [obj release] } 

Entonces, realmente no necesitamos autorelease.

Autorelease como un mecanismo que aún es utilizado por ARC, además, el código comstackdo de ARC está diseñado para interoperar sin problemas con el código comstackdo de MRC, por lo que la maquinaria de autorelease está cerca.

En primer lugar, no piense en términos de recuentos de reference, sino en términos de interés de propiedad, siempre que exista un interés de propiedad declarado en un object, entonces el object vive, cuando no hay interés de propiedad, se destruye. En MRC declara el interés de la propiedad al usar retain o al crear un nuevo object; y renuncias al interés de la propiedad mediante el uso de la release .

Ahora, cuando un método de llamada crea un object y desea devolverlo a su interlocutor, el interlocutor se va, por lo que debe renunciar a los intereses de la propiedad, por lo que el interlocutor debe declarar su interés de propiedad o el object puede ser destruido. Pero hay un problema, la llamada finaliza antes de que la persona que llama reciba el object, de modo que cuando la persona que llama renuncia a su propiedad, el object puede ser destruido antes de que el que llama tenga la oportunidad de declarar su interés, no es bueno.

Se usan dos soluciones para abordar esto:

1) Se declara que el método transfiere el interés de la propiedad en su valor de retorno de la llamada a la persona que llama: este es el model utilizado para los methods init , copy , etc. El vendedor nunca notifica que está renunciando a su interés de propiedad, y el vendedor nunca declara el interés de la propiedad: por acuerdo, la persona que llama se hace cargo del interés de la propiedad y la responsabilidad de renunciar posteriormente.

2) Se declara que el método devuelve un valor en el que la persona que llama no tiene interés en la propiedad, pero que otra persona mantendrá un interés de propiedad durante un corto período de time, generalmente hasta el final del ciclo de ciclo de ejecución actual. Si la persona que llama quiere usar el valor de retorno más largo que eso debe declarar su propio interés de propiedad, pero de lo contrario puede confiar en que otra persona tenga un interés de propiedad y, por lo tanto, el object se mantenga cerca.

La pregunta es ¿quién puede ser esa "persona" que mantiene el interés de la propiedad? No puede ser el método callee ya que está a punto de desaparecer. Ingrese el "pool de autorelease": este es solo un object al cual cualquier persona puede transferir un interés de propiedad para que el object permanezca por un time. El set de autorelease renunciará a su interés de propiedad en todos los objects que se le transfieren de esta forma cuando se le indique hacerlo, generalmente al final del ciclo de ciclo de ejecución actual.

Ahora bien, si lo anterior tiene algún sentido (es decir, si lo expliqué claramente), puede ver que el método (2) no es realmente necesario ya que siempre se puede usar el método (1); pero , y es crucial, pero , en MRC, es mucho más trabajo para el progtwigdor, ¿cada valor recibido de un método viene con un interés de propiedad que debe administrarse y abandonarse en algún momento? ¿generar una secuencia solo para generarla? Bueno, entonces debes renunciar a tu interés en esa cadena temporal … Entonces (2) hace la vida mucho más fácil.

Las computadoras de la otra mano son idiotas rápidas, y contando cosas e insertando códigos para renunciar a los intereses de la propiedad en nombre de los progtwigdores inteligentes es algo que están bien adaptados. Entonces, ARC no necesita el grupo de liberación automática. Pero puede hacer las cosas más fáciles y más eficientes, y detrás de escena, ARC optimiza su uso: mire la salida del ensamblador en Xcode y verá llamadas a rutinas con un nombre similar a "retainAutoreleasedReturnValue" …

Entonces tienes razón, no es necesario , pero sigue siendo útil, pero en ARC puedes (generalmente) olvidarlo.

¡HTH más de lo que probablemente confunda!

se utiliza la function de autorización automática para el object de function devuelto, por lo que la persona que llama no se apropiará y el destinatario liberará el object en el futuro.

Si se autorealiza, se agregará al grupo de autorelease. Cuando se vacía el set de autorelease, se realizará la liberación diferida. una function / método no necesita devolver un object autoelevado (por ejemplo, podría ser un ivar que no recibió un ciclo de retención / autorealización).

Sin embargo, ARC es capaz de contar la propiedad de la persona que llama y liberarla después del uso, es decir, puede comportarse como Smart Pointer en C ++. Con ARC, puede deshacerse de autorelease porque autorelease no es determinista.

Tiene el potencial para No hay garantía El mayor "problema" aquí es que el comstackdor no conoce / cuida la mecánica de la memory del object devuelto de una llamada arbitraria. No puede asumir cómo se devuelve un object porque ARC es una nueva adición que es anterior a MRC. Esto es importante porque hace que los progtwigs ARC sean compatibles con los progtwigs que usan retener / liberar manualmente. Por ejemplo, Foundation.framework puede usar ARC, o puede usar MRC, o puede usar ambos. También puede llamar a las API que se crearon utilizando cadenas de herramientas más antiguas. Entonces, esto tiene la ventaja de mantener utilizable una tonelada de código existente.

La razón por la que solicito esta pregunta es que veo las llamadas de object devuelto dealloc antes en ARC que el código no ARC.

Hay una forma opcional de devolver un object: consulte la respuesta de CRD (+1) sobre el ensamblaje y las llamadas a las inserciones del comstackdor para realizar operaciones de recuento de references, por ejemplo, retainAutoreleasedReturnValue .

En cualquier caso, no hay garantía de que las vidas se networkingucirán siempre en ARC. Un progtwigdor que entiende la ejecución de su progtwig puede minimizar las operaciones de recuento de vidas y ref porque ARC tiene requisitos de propiedad y de vida más estrictos.

Esto me lleva a pensar que ARC puede comportarse como Smart Pointer y puede inutilizar el autoelemento. ¿Es verdad o posible?

En teoría, no veo por qué las agrupaciones de autorelease no pueden eliminarse para un nuevo sistema . Sin embargo, creo que hay demasiado código existente que depende de las agrupaciones autorelease para levantar esa restricción; creo que necesitarían introducir un nuevo formatting ejecutable (como fue el caso con ObjC Garbage Collection) y revisar una tonelada de API existentes y progtwigs para una transición tan significativa para tener éxito. Además, algunas API probablemente solo deban ser eliminadas. Es posible que las API necesiten algo de fortalecimiento en relación con la propiedad para lograr esto, pero la mayor parte de eso está completo en los progtwigs que ya se han migrado a ARC. Heck, incluso el comstackdor podría (se extendió a) utilizar internamente una forma de pointers inteligentes para pasar y devolver types objc y las agrupaciones de autorelease podrían eliminarse en dicho sistema. Nuevamente, eso requeriría una gran cantidad de código para migrar. Entonces, una actualización como ARC V2.

Lo único que puedo pensar sobre la utilidad de autorelease está en multiprocess o código de networking porque no puede ser más fácil contar la propiedad cuando el object está pasando.

No es un problema: los pools de autorelease son subprocesss locales. No veo un problema más allá de ese sistema (a less que dependa de una condición de carrera, lo que obviamente es una mala idea).

Diferencia entre ARC y autorelease explicada en el código:

ARC:

 -somefunc { id obj = [NSArray array]; NSLog(@"%@", obj); // ARC now calls release for the first object id obj2 = [NSArray array]; NSLog(@"%@", obj2); // ARC now calls release for the second object } 

Autorelease:

 -somefunc { id obj = [NSArray array]; NSLog(@"%@", obj); id obj2 = [NSArray array]; NSLog(@"%@", obj2); } // Objects are released some time after this 

Básicamente, ARC funciona una vez que una variable ya no se usa en un ámbito, mientras que el autorelease espera hasta que alcanza el bucle principal y luego llama a la release en todos los objects del grupo. ARC se usa dentro del scope, el autorelease se usa fuera del scope de la function.

autorelease todavía se usa en ARC. ARC solo te llama y es inteligente sobre cortocircuitarlo. Aquí hay una demostración de cómo funciona eso, que copyré aquí en caso de que la publicación del blog desaparezca alguna vez; Todo el crédito de Matt Galloway.

Entonces considere el siguiente método:

 void foo() { @autoreleasepool { NSNumber *number = [NSNumber numberWithInt:0]; NSLog(@"number = %p", number); } } 

Esto es totalmente artificial, por supuesto, pero debería dejarnos ver lo que está sucediendo. En tierras no ARC, asumiríamos que ese número se asignaría dentro del número ConInt: y se devolvió el autorelementado. Entonces, cuando el set de autorelease sea drenado, será liberado. Entonces veamos si eso sucedió (como siempre, esto es instrucciones de ARMv7):

  .globl _foo .align 2 .code 16 .thumb_func _foo _foo: push {r4, r7, lr} add r7, sp, #4 blx _objc_autoreleasePoolPush movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) movs r2, #0 movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) mov r4, r0 movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) LPC0_0: add r1, pc movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) LPC0_1: add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend mov r1, r0 movw r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4)) movt r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4)) LPC0_2: add r0, pc blx _NSLog mov r0, r4 blx _objc_autoreleasePoolPop pop {r4, r7, pc} 

Bueno, sí. Eso es exactamente lo que está sucediendo. Podemos ver la llamada para empujar una agrupación de autorelease, luego una llamada a numberWithInt: luego una llamada para abrir una agrupación de autorelease. Exactamente lo que esperaríamos. Ahora veamos exactamente el mismo código comstackdo en ARC:

  .globl _foo .align 2 .code 16 .thumb_func _foo _foo: push {r4, r5, r7, lr} add r7, sp, #8 blx _objc_autoreleasePoolPush movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) movs r2, #0 movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) mov r4, r0 movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) LPC0_0: add r1, pc movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) LPC0_1: add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend @ InlineAsm Start mov r7, r7 @ marker for objc_retainAutoreleaseReturnValue @ InlineAsm End blx _objc_retainAutoreleasedReturnValue mov r5, r0 movw r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4)) movt r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4)) mov r1, r5 LPC0_2: add r0, pc blx _NSLog mov r0, r5 blx _objc_release mov r0, r4 blx _objc_autoreleasePoolPop pop {r4, r5, r7, pc} 

Observe las llamadas a objc_retainAutoreleasedReturnValue y objc_release. Lo que está sucediendo allí es que ARC ha determinado para nosotros que realmente no necesita preocuparse por el grupo de autorelease que está en su lugar, porque simplemente puede decirle a la autorelease que no ocurra (con la llamada a objc_retainAutoreleasedReturnValue) y luego liberar el object más tarde sí mismo. Esto es deseable porque significa que la lógica de autorealización no tiene que suceder.

Tenga en count que el grupo de autorelease todavía debe ser presionado y reventado porque ARC no puede saber qué está sucediendo en las llamadas a numberWithInt: y NSLog para saber si los objects se includeán en el grupo allí. Si supiera que no autorizaron nada, entonces podrían deshacerse del impulso y el pop. Tal vez ese tipo de lógica vendrá en versiones futuras aunque no estoy muy seguro de cómo funcionaría la semántica de eso.

Ahora consideremos otro ejemplo que es donde queremos usar el número fuera del scope del bloque del pool de autorelease. Esto debería mostrarnos por qué ARC es una maravilla para trabajar. Considere el siguiente código:

 void bar() { NSNumber *number; @autoreleasepool { number = [NSNumber numberWithInt:0]; NSLog(@"number = %p", number); } NSLog(@"number = %p", number); } 

Es posible que (correctamente) pienses que esto va a causar problemas aunque parezca perfectamente inocuo. Es un problema porque el número se asignará dentro del bloque del set de autorelease, se desasignará cuando el set de autorelease aparece, pero luego se usa después de que se ha desasignado. ¡UH oh! Veamos si estamos en lo correcto al comstackrlo sin ARC habilitado:

  .globl _bar .align 2 .code 16 .thumb_func _bar _bar: push {r4, r5, r6, r7, lr} add r7, sp, #12 blx _objc_autoreleasePoolPush movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) movs r2, #0 movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) mov r4, r0 movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) LPC1_0: add r1, pc movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) LPC1_1: add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend movw r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4)) movt r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4)) LPC1_2: add r6, pc mov r5, r0 mov r1, r5 mov r0, r6 blx _NSLog mov r0, r4 blx _objc_autoreleasePoolPop mov r0, r6 mov r1, r5 blx _NSLog pop {r4, r5, r6, r7, pc} 

Obviamente, no hay llamadas para retener, liberar o autorizar, como era de esperar, ya que no hemos hecho ninguna explícitamente y no estamos usando ARC. Podemos ver aquí que se compiló exactamente como cabría esperar de nuestro razonamiento anterior. Veamos cómo se ve cuando ARC nos ayuda:

  .globl _bar .align 2 .code 16 .thumb_func _bar _bar: push {r4, r5, r6, r7, lr} add r7, sp, #12 blx _objc_autoreleasePoolPush movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) movs r2, #0 movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) mov r4, r0 movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) LPC1_0: add r1, pc movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) LPC1_1: add r0, pc ldr r1, [r1] ldr r0, [r0] blx _objc_msgSend @ InlineAsm Start mov r7, r7 @ marker for objc_retainAutoreleaseReturnValue @ InlineAsm End blx _objc_retainAutoreleasedReturnValue movw r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4)) movt r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4)) LPC1_2: add r6, pc mov r5, r0 mov r1, r5 mov r0, r6 blx _NSLog mov r0, r4 blx _objc_autoreleasePoolPop mov r0, r6 mov r1, r5 blx _NSLog mov r0, r5 blx _objc_release pop {r4, r5, r6, r7, pc} 

¡Una ronda de aplausos para ARC, por favor! Observe que se ha dado count de que estamos utilizando el número fuera del scope del bloque de agrupación de autorelease, por lo que se retiene el valor de retorno de numberWithInt: tal como lo hizo antes, pero esta vez se coloca la versión al final de la function de barra en lugar de antes se reenvía el grupo de autorelease. Eso nos habrá ahorrado un locking en algún código que podríamos haber pensado que era correcto, pero que en realidad tenía un sutil error de administración de memory.

Sin embargo, ARC es capaz de contar la propiedad de la persona que llama y liberarla después del uso, es decir, puede comportarse como Smart Pointer en C ++. Con ARC, puede deshacerse de autorelease porque autorelease no es determinista.

Está confundiendo ARC con el recuento de references. Objective-C siempre se ha basado en el conteo de references para la gestión de la memory. ARC continúa esta tradición y simplemente elimina la necesidad de que el progtwigdor inserte manualmente las llamadas apropiadas para -retain , -autorelease y -autorelease . En ARC, el comstackdor inserta estas llamadas, pero el mecanismo de conteo de references sigue siendo el mismo que siempre.

ARC no elimina la necesidad de autorelease, pero puede evitarlo en situaciones en las que un humano normalmente lo hubiera usado.

Intereting Posts