Aux débuts d’Objective-C et de Cocoa, les développeurs devaient gérer eux-mêmes les allocations et libérations de mémoires pour leurs objets avec les méthodes alloc
, retain
, release
.
À chaque emplacement de mémoire est associé un compteur de références, chaque appel à alloc
ou retain
augmente ce compteur, chaque appel à release
diminue ce compteur. Lors d’un release
, si le compteur passe à zéro, ça signifie qu’aucun objet dans le code ne fait plus référence à cet emplacement. Il doit donc être libéré. Si le compteur est encore supérieur à zéro, release
ne fait rien.
Avec l’ARC (Automatic Reference counting), le compilateur se charge de placer lui-même ces mêmes méthodes aux endroits appropriés, évitant ce travail aux développeurs, et garantissant un équilibre parfait entre les retain
et les release
. Sauf que pas toujours…
Certaines fonctions fournies par les frameworks d’Apple peuvent vous retourner des Unmanaged
. Vous devez pour ces objets décider de la stratégie à adopter. C’est notamment le cas lors que vous manipulez des objets issus de Core Graphics (CG…) ou Core Foundation (CF…).
Exemple, dans la classe AVCapturePhoto
:
func cgImageRepresentation() -> Unmanaged<CGImage>?
Cette fonction retourne une Unmanaged CGImage
.
Pour récupérer l’objet CGImage lui-même, il faut faire appel à l’une des deux fonctions
• takeUnretainedValue()
qui n’incrémente pas le compteur de référence
• takeRetainedValue()
qui incrémente le compteur de référence.
Mais laquelle utiliser ?
En règle générale, si le nom de la fonction qui retourne l’objet Unmanaged contient Create ou Copy, vous utiliserez takeRetainedValue()
, sinon c’est takeUnretainedValue()
qui convient.
Dans cet exemple :
...
let unmanagedCGImage = capturePhoto.cgImageRepresentation()
let cgImage = unmanagedCGImage.takeUnretainedValue()
...