Swift: Que faire d’un objet ‘Unmanaged’

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()
...