El conteo automático de referencias ( ARC ) es una función de gestión de memoria del compilador Clang que proporciona un conteo automático de referencias para los lenguajes de programación Objective-C y Swift . En tiempo de compilación, inserta en el código objeto mensajes y [1] [2] que aumentan y disminuyen el conteo de referencias en tiempo de ejecución, marcando para la desasignación aquellos objetos cuando el número de referencias a ellos llega a cero. retain
release
ARC se diferencia del seguimiento de la recolección de basura en que no hay un proceso en segundo plano que desasigne los objetos de forma asincrónica en tiempo de ejecución. [3] A diferencia del seguimiento de la recolección de basura, ARC no maneja los ciclos de referencia automáticamente. Esto significa que mientras haya referencias "fuertes" a un objeto, no se desasigne. Las referencias cruzadas fuertes pueden crear bloqueos y fugas de memoria . Depende del desarrollador romper los ciclos mediante el uso de referencias débiles . [4]
Apple Inc. implementa ARC en sus sistemas operativos, como macOS ( OS X ) e iOS . El soporte limitado (ARCLite) [5] ha estado disponible desde Mac OS X Snow Leopard y iOS 4 , con soporte completo a partir de Mac OS X Lion y iOS 5. [ 6] La recolección de basura se declaró obsoleta en OS X Mountain Lion , a favor de ARC, y se eliminó de la biblioteca de tiempo de ejecución Objective-C en macOS Sierra . [7] [8]
El compilador aplica las siguientes reglas cuando ARC está activado:
retain
, release
, retainCount
, autorelease
o dealloc
no se pueden enviar a objetos. En su lugar, el compilador inserta estos mensajes en tiempo de compilación automáticamente, incluso [super dealloc]
cuando dealloc
se anula. [9]// Sin ARC - ( void ) dealloc { [[ NSNotificationCenter defaultCenter ] removeObserver : self ]; [ super dealloc ]; } // Con ARC - ( void ) dealloc { [[ NSNotificationCenter defaultCenter ] removeObserver : self ]; // [super dealloc] se llama automáticamente }
id
y void *
. [9] Esto incluye conversiones entre objetos Foundation y objetos Core Foundation. Los programas deben utilizar conversiones especiales, o llamadas a funciones especiales, para proporcionar al compilador más información sobre la duración de un objeto.// Sin ARC - ( NSString * ) giveMeAString { CFStringRef myString = [ self someMethodThatCreatesACFString ]; NSString * newString = ( NSString * ) myString ; return [ newString autorelease ]; } // Con ARC - ( NSString * ) giveMeAString { CFStringRef myString = [ self someMethodThatCreatesACFString ]; // el recuento de retención es 1 NSString * newString = ( __bridge_transfer NSString * ) myString ; // la propiedad ahora se ha transferido a ARC return newString ; }
NSAutoreleasePool
se puede crear un objeto para este propósito. ARC utiliza @autoreleasepool
bloques, que encapsulan la asignación de los objetos temporales y los desasignan cuando se llega al final del bloque. [9] // Sin ARC - ( void ) loopThroughArray: ( NSArray * ) array { for ( id object in array ) { NSAutoreleasePool * pool = [[ NSAutoreleasePool alloc ] init ]; // Crea muchos objetos temporales [ pool drain ]; } } // Con ARC - ( void ) loopThroughArray: ( NSArray * ) array { for ( id object in array ) { @autoreleasepool { // Crea muchos objetos temporales } } }
NSAllocateObject
y NSDeallocateObject
[9]struct
s) [9]NSZone
) [9]new
. [9]ARC introduce algunos nuevos atributos de declaración de propiedades, algunos de los cuales reemplazan los atributos antiguos.
Poner a cero las referencias débiles es una característica de Objective-C ARC que borra automáticamente (establece en nil
) las variables locales de referencia débil, las variables de instancia y las propiedades declaradas inmediatamente antes de que el objeto al que se apunta comience a desasignarse. Esto garantiza que el puntero vaya a un objeto válido o nil
, y evita punteros colgantes . Antes de la introducción de esta característica, las "referencias débiles" hacían referencia a referencias que no se retenían, pero que no se establecían en nil
cuando se desasignaba el objeto al que apuntaban (equivalente a unsafe_unretained
en ARC), lo que posiblemente condujera a un puntero colgante. El programador normalmente tenía que asegurarse de que todas las posibles referencias débiles a un objeto se establecieran en nulo manualmente cuando se desasignaba. Poner a cero las referencias débiles evita la necesidad de hacer esto.
La puesta a cero de referencias débiles se indica mediante el uso del atributo de propiedad declarado weak
o mediante el uso del atributo de variable __weak
.
La puesta a cero de referencias débiles solo está disponible en Mac OS X Lion (10.7) o posterior y iOS 5 o posterior, porque requiere soporte adicional del entorno de ejecución Objective-C. Sin embargo, algunas clases de OS X actualmente no admiten referencias débiles. [9] El código que usa ARC pero necesita admitir versiones del sistema operativo anteriores a las anteriores no puede usar la puesta a cero de referencias débiles y, por lo tanto, debe usar unsafe_unretained
referencias débiles. Existe una biblioteca de terceros llamada PLWeakCompatibility [1] que permite usar la puesta a cero de referencias débiles incluso en estas versiones anteriores del sistema operativo.
Xcode 4.2 o posterior proporciona una forma de convertir código a ARC. [10] A partir de Xcode 4.5, se encuentra eligiendo Editar > Refactorizar > Convertir a Objective-C ARC... Aunque Xcode convertirá automáticamente la mayor parte del código, es posible que parte del código deba convertirse manualmente. Xcode informará al desarrollador cuando surjan casos de uso más complejos, como cuando se declara una variable dentro de un grupo de liberación automática y se usa fuera de él o cuando dos objetos deben conectarse sin costo con conversiones especiales.
En Swift, las referencias a objetos son fuertes, a menos que se declaren weak
o unowned
. Swift requiere el manejo explícito de nil con el tipo Opcional: un tipo de valor que puede tener un valor o ser nulo. Un tipo Opcional debe manejarse "desenvolviéndolo" con una declaración condicional , lo que permite el uso seguro del valor, si está presente. Por el contrario, cualquier tipo que no sea Opcional siempre tendrá un valor y no puede ser nulo.
var myString : String // Solo puede ser una cadena var myOtherString : String ? // Puede ser una cadena o nulosi deja que myString = myOtherString { // Desenrolle la impresión opcional ( myString ) // Imprima la cadena, si está presente }
En consecuencia, una referencia fuerte a un objeto puede ser tanto de tipo opcional como no opcional (la opcionalidad y la fuerza de la referencia son conceptos diferentes, aunque relacionados). Una referencia débil siempre es de tipo opcional, ya que el objeto puede desasignarse y la referencia se establece automáticamente en nula. Las referencias sin propietario son como las referencias débiles, pero ARC no las establece en nula automáticamente. Pueden ser no opcionales u opcionales. Se espera que una referencia sin propietario siempre tenga un valor, por lo que acceder al valor de una referencia sin propietario después de que se haya desasignado la instancia referenciada dará como resultado un error de tiempo de ejecución. [11]
var strongReference : MyClass // Referencia fuerte no opcional, no puede ser nula var strongOptionalReference : MyClass ? // Referencia fuerte opcional, puede ser nula (manualmente) weak var weakReference : MyClass ? // Referencia débil, siempre opcional, puede ser nula (automática o manualmente) unowned var unownedReference : MyClass // Referencia no opcional sin propietario, no puede ser nula
Swift también se diferencia de Objective-C en su uso y fomento de tipos de valor en lugar de tipos de referencia . La mayoría de los tipos en la biblioteca estándar de Swift son tipos de valor y se copian por valor, mientras que las clases y los cierres son tipos de referencia y se pasan por referencia. Debido a que los tipos de valor se copian cuando se pasan, se desasignan automáticamente cuando el programa abandona el ámbito que los contiene. [11] [12]