sur le tas passe par les appels systèmes connus de la librarie C Allocation des objets sur la pile quasi‑interdite (sauf les fermetures = blocks) Langage dynamique grâce au moteur d'exécution (différent de C, C++, ASM, LISP,...)
compteur est nul Classe 'racine' : NSObject Chaque objet hérite de NSObject directement ou indirectement : c'est lui qui gère l'allocation/désallocation pour tous ses enfants
t a t i o n M A O b j e c t { C l a s s i s a ; v o l a t i l e i n t 3 2 _ t r e t a i n C o u n t ; / / C o m p t e u r d e r é f é r e n c e } + ( i d ) a l l o c { / / A p p e l a u m o t e u r d ' é x e c u t i o n p o u r i n s t a n c i e r M A O b j e c t * o b j = c a l l o c ( 1 , c l a s s _ g e t I n s t a n c e S i z e ( s e l f ) ) ; o b j - > i s a = s e l f ; o b j - > r e t a i n C o u n t = 1 ; / / M i s e à 1 r e t u r n o b j ; } - ( i d ) r e t a i n { / / I n c r é m e n t a t i o n a t o m i q u e O S A t o m i c I n c r e m e n t 3 2 ( & r e t a i n C o u n t ) ; r e t u r n s e l f ; } - ( o n e w a y v o i d ) r e l e a s e { / / D é c r é m e n t a t i o n a t o m i q u e u i n t 3 2 _ t n e w C o u n t = O S A t o m i c D e c r e m e n t 3 2 ( & r e t a i n C o u n t ) ; i f ( n e w C o u n t = = 0 ) / / S i l e c o m p t e u r < 0 - > d é s a l l o c a t i o n [ s e l f d e a l l o c ] ; } Source : NSBlog ‑ Mike Ash
l l o c { / / A p p e l s y s t è m e s t a n d a r d f r e e ( s e l f ) ; } - ( i d ) i n i t { r e t u r n s e l f ; } - ( i d ) a u t o r e l e a s e { [ N S A u t o r e l e a s e P o o l a d d O b j e c t : s e l f ] ; r e t u r n s e l f ; } - ( N S U I n t e g e r ) r e t a i n C o u n t { r e t u r n r e t a i n C o u n t ; } L'utilisation du moteur d'exécution dans la fonction alloc : M A O b j e c t * o b j = c a l l o c ( 1 , c l a s s _ g e t I n s t a n c e S i z e ( s e l f ) ) ; permet d'allouer la mémoire pour tout les objets.
renvoie une objet dont le compteur de référence vaut 1 Dans les autres cas, nous ne sommes pas responsable du cycle de vie de l'objet, c'est un autre objet quelque part qui gère le cycle de vie. Dans ces cas, on doit faire appel à release ou retain si l'on souhaite intervenir sur ce cycle de vie. Un appel à retain incrémente le compteur de 1 Un appel à release décrémente le compteur de 1 Un alloc, copy, new, retain implique un retain ou autorelease
s t r i n g = [ N S S t r i n g s t r i n g W i t h F o r m a t : @ " H e l l o % p " , s e l f ] ; / / O n n e p o s s è d e p a s l ' o b j e t - > p a s à g é r e r l a d é s a l l o c a t i o n / / c ' e s t à d i r e q u ' u n o b j e t f e r a u n r e l e a s e p l u s t a r d [ s t r i n g r e t a i n ] ; / / I n t e r v e n t i o n s u r l e c y c l e d e v i e - > à n o u s d e f a i r e u n r e l e a s e p l u s t a r d / / R e f C o u n t e r = 2 [ s t r i n g r e l e a s e ] ; / / R e f c o u n t e r = 1 / / I l f a u t a j o u t e r l e r e l e a s e d e l ' o b j e t q u i l e g è r e i n i t i a l e m e n t / / A l o r s R e f c o u n t e r v a u d r a 0 / * . . . * / / / N S U R L C o n n e c t i o n D e l e g a t e - ( v o i d ) c o n n e c t i o n : ( N S U R L C o n n e c t i o n * ) c o n n e c t i o n d i d F a i l W i t h E r r o r : ( N S E r r o r * ) e r r o r { / / O n n e p o s s è d e n i e r r o r , n i c o n n e c t i o n - > u n a u t r e o b j e t g è r e l e u r c y c l e d e v i e [ e r r o r r e t a i n ] ; / / I n t e r v e n t i o n s u r l e c y c l e d e v i e }
les derniers objet ayant appellé alloc, copy, new, retain ou équivalents et n'ayant pas appellé release par la suite. Comme aucune allocation d'objet sur la pile n'est tolérée, lorsque l'on parle de propriétaires, on dit que le pointeur possède l'objet qu'il pointe en mémoire.
f o o = [ [ N S S t r i n g a l l o c ] i n i t ] ; / / f o o - > ( N S S t r i n g @ 0 x F E B C D ) / / L e p o i n t e u r ' f o o ' p o s s è d e l ' o b j e t à l ' a d r e s s e 0 x F E B C D - R e f C o u n t = 1 N S S t r i n g * f o o 2 = [ f o o r e t a i n ] ; / / f o o e t f o o 2 - > ( N S S t r i n g @ 0 x F E B C D ) / / L e s d e u x p o i n t e u r s p o s s è d e l ' o b j e t à l ' a d r e s s e 0 x F E B C D - R e f C o u n t = 2 [ f o o r e l e a s e ] ; / / f o o n e p o s s è d e p l u s l ' o b j e t à l ' a d r e s s e 0 x F E B C D - R e f C o u n t = 1 / / f o o 2 l e p o s s è d e e n c o r e [ f o o 2 r e l e a s e ] ; / / P l u s p e r s o n n e n e p o s s è d e l ' o b j e t - R e f C o u n t = 0 - > d é s a l l o c a t i o n
la méthode alloc de NSObject F o o * f o o = [ F o o a l l o c ] ; Initialisation Allouer la classe ne suffit pas, il nous faut l'initialiser. / / E r r e u r : i n i t p e u t r e n v o y e r u n é l é m e n t d i f f é r e n t d e a l l o c F o o * f o o = [ F o o a l l o c ] ; [ f o o i n i t O f F o o ] ; / / C o n s i d é r é c o m m e m a u v a i s e p r a t i q u e F o o * f o o = [ F o o n e w ] ; / / É q u i v a l e n t à a l l o c i n i t / / B o n n e p r a t i q u e F o o * f o o = [ [ F o o a l l o c ] i n i t O f F o o ] ;
n t e r f a c e T S h i r t { N S U I n t e g e r _ t a i l l e ; N S C o l o r * _ c o u l e u r ; } @ e n d Quelles sont les bonnes pratiques pour l'initialisation ?
c'est celui qui est en charge d'initialiser toutes les valeurs qui conditionnent la vie de l'objet @ i m p l e m e n t a t i o n T S h i r t - ( i d ) i n i t W i t h T a i l l e : ( N S U I n t e g e r * ) t a i l l e A n d C o u l e u r : ( N S C o l o r * ) c o u l e u r { i f ( s e l f = [ s u p e r i n i t ] ) { _ t a i l l e = t a i l l e _ c o u l e u r = [ c o u l e u r r e t a i n ] ; } r e t u r n s e l f ; } @ e n d
appeler l'initialiseur désigné @ i m p l e m e n t a t i o n T S h i r t / / . . . - ( i d ) i n i t W i t h T a i l l e : ( N S U I n t e g e r ) t a i l l e { N S C o l o r * d e f a u t = [ N S C o l o r r e d C o l o r ] ; r e t u r n [ s e l f i n i t W i t T a i l l e : t a i l l e A n d C o u l e u r : d e f a u l t ] ; } - ( i d ) i n i t W i t h C o l o r : ( N S C o l o r * ) c o u l e u r { N S U I n t e g e r d e f a u l t = 3 6 ; r e t u r n [ s e l f i n i t W i t T a i l l e : d e f a u l t A n d C o u l e u r : c o u l e u r ] ; } @ e n d
dans les méthodes init et dealloc Accès direct à la variable (NB : on peut utiliser l'opérateur ‑>) Utilisation des accesseurs peut déclencher des notifications KVC/KVO, des effets de bords liées à des accesseurs/mutateurs personnalisés ou surchargés dans les classes filles
Libérer les ressources non désallouées dans dealloc (objet, connexion ultérieurement libérée dans init,...) 2. Libérer self qui possède un compteur de 1 à cause de l'appel à alloc 3. Retournez nil
t a t i o n T a b l e a u x / / P o s s è d e d e u x i V a r : _ t a b 1 - > N S M u t a b l e A r r a y e t _ t a b 2 - > N S A r r a y - ( i d ) i n i t { i f ( [ s e l f = s u p e r i n i t ] ) / / R e f C o u n t e r = 1 { _ t a b 1 = [ [ N S M u t a b l e A r r a y a l l o c ] i n i t ] ; i f ( ! _ t a b ) / / S i e r r e u r { [ s e l f r e l e a s e ] ; / / R e f C o u n t = 0 - > s e l f d e a l l o c r e t u r n n i l ; / / R e t o u r e r r e u r } _ t a b 2 = [ [ N S A r r a y a l l o c ] i n i t W i t h C o n t e n t s O f F i l e : @ " … " ] ; i f ( ! _ t a b 2 ) { [ s e l f r e l e a s e ] ; / / R e f C o u n t = 0 - > s e l f d e a l l o c r e t u r n n i l ; / / R e t o u r e r r e u r ; } } r e t u r l s e l f ; } - ( v o i d ) d e a l l o c { [ _ t a b 1 r e l e a s e ] ; / / D é s a l l o c a t i o n [ _ t a b 2 r e l e a s e ] ; / / D é s a l l o c a t i o n [ s u p e r d e a l l o c ] ; / / R a p p e l : e n v o y e r u n m e s s a g e à n i l n e f a i t r i e n / / - > p a s b e s o i n d e t e s t e r i f ( ! _ t a b 1 ) [ _ t a b 1 r e l e a s e ] ; }
la méthode dealloc de la classe Bon exemple: - ( v o i d ) d e a l l o c { [ _ c o u l e u r r e l e a s e ] ; [ s u p e r d e a l l o c ] ; / / N S O b j e c t s e c h a r g e d e d é s a l l o u e r } Mauvais exemple: - ( v o i d ) d e a l l o c { [ s u p e r d e a l l o c ] ; / / D é s a l l o c a t i o n d e l a c l a s s e [ _ c o u l e u r r e l e a s e ] ; / / E r r e u r p o i n t e u r i n v a l i d e c a r d é s a l l o u é }
mettre des variables à nil dans dealloc On peut se dire que si l'appel à [super dealloc] désalloue la classe, ce n'est pas nécessaire d'appeler release
e A : N S O b j e c t { } @ e n d @ i n t e r f a c e B : N S O b j e c t { A * a ; } - ( i d ) d e a l l o c { [ a r e l e a s e ] ; [ s u p e r d e a l l o c ] ; } @ e n d @ i n t e r f a c e : N S O b j e c t C { A * a ; } - ( i d ) d e a l l o c { [ s u p e r d e a l l o c ] ; [ a r e l e a s e ] ; / / R e l e a s e n ' e s t j a m a i s e n v o y é à a } @ e n d A * a = [ [ A a l l o c ] i n i t ] ; / / a R e f C o u n t e r = 1 B * b = [ [ B a l l o c ] i n i t ] ; C * c = [ [ C a l l o c ] i n i t ] ; B - > a = [ a r e t a i n ] ; / / a R e f C o u n t e r = 2 C - > a = [ a r e t a i n ] ; / / a R e f C o u n t e r = 3 [ a r e l e a s e ] ; / / a R e f C o u n t e r = 2 [ b r e l e a s e ] ; / / a R e f C o u n t e r = 1 - > m e s s a g e r e l e a s e e n v o y é d a n s d e a l l o c d e B [ c r e l e a s e ] ; / / a R e f C o u n t e r = 1 - > m e s s a g e n o n e n v o y é - > f u i t e m é m o i r e
version mutable et une version immuable Immuable : l'objet pointé en mémoire est immuable Mutable : l'objet pointé en mémoire est mutable Objet immuable ne veut pas dire pointeur immuable
mémoire ne change pas (immuable) = copie superficielle. Copie d'un objet mutable = copie profonde Copie mutable d'un objet immuable : utilisation de mutableCopyWithZone:
immuable : N S S t r i n g * s t r i n g 1 = @ " S t r i n g 1 " ; s t r i n g 1 = @ " A u t r e c h o s e q u e S t r i n g 1 " ; / / L e p o i n t e u r p e u t c h a n g e r / / @ " S t r i n g 1 " n e c h a n g e p a s e n m é m o i r e La méthode copy de NSString incrémente le compteur de référence de l'objet et renvoie le même objet pointé : N S S t r i n g * s t r i n g 1 = @ " H E L L O " ; N S S t r i n g * c o p y O f S t r i n g 1 = [ s t r i n g 1 c o p y ] ; B O O L e q u a l = ( s t r i n g 1 = = c o p y O f S t r i n g 1 ) ; / / - > e q u a l = Y E S Copie mutable à partir d'un objet immuable : N S S t r i n g * s t r 1 = @ " H e l l o " ; N S M u t a b l e S t r i n g * s t r 2 = [ s t r 1 m u t a b l e C o p y ] ; [ s t r 2 a p p e n d S t r i n g : @ " m u t a b l e " ] ;
i e s u p e r f i c e l l e - ( i d ) c o p y W i t h Z o n e : ( N S Z o n e * ) { r e t u r n [ s e l f r e t a i n ] ; } / / U n e c o p i e p r o f o n d e ( c l a s s e h é r i t a n t d e N S O b j e c t d i r e c t e m e n t ) / / C l a s s e T S h i r t - ( i d ) c o p y W i t h Z o n e : ( N S Z o n e * z o n e ) { / / [ s e l f c l a s s ] o b l i g a t o i r e p o u r l e s c l a s s e s f i l l e s i d c o p i e = [ [ [ s e l f c l a s s ] a l l o c W i t h Z o n e : z o n e ] i n i t W i t h T a i l l e : [ s e l f t a i l l e ] A n d C o u l e u r : [ s e l f c o u l e u r ] ] ; r e t u r n c o p i e ; } / / U n e c o p i e p r o f o n d e ( c l a s s e f i l l e d o n t l a m è r e i m p l é m e n t e u n e c o p y ) / / C l a s s e h é r i t a n t d e T S h i r t - ( i d ) c o p y W i t h Z o n e : ( N S Z o n e * z o n e ) { i d c o p i e = [ s u p e r c o p y W i t h Z o n e : z o n e ] ; / * A u t r e o p é r a t i o n s é v e n t u e l l e s * / r e t u r n c o p i e ; }
mémoires contigues comme en C Les collections ne font que garder des listes des pointeurs et agissent sur les compteurs de références des objets qu'elles contiennent Ajouter un objet dans une collection incrémente le compteur de référence de l'objet Retirer un objet d'une collection décrémente le compteur de référence de l'objet
a = [ [ N S S t r i n g a l l o c ] i n i t ] ; / / R e f C o u n t e r a = 1 N S S t r i n g * b = [ [ N S S t r i n g a l l o c ] i n i t ] ; / / R e f C o u n t e r b = 1 N S A r r a y * a r r a y = [ [ N S A r r a y a l l o c ] i n t i W i t h O b j e c t s : a , b , n i l ] ; / / R e f C o u n t e r a r r a y = 1 / / R e f C o u n t e r a = 2 - R e f C o u n t e r b = 2 [ a r e l e a s e ] ; / / R e f C o u n t e r a = 1 [ b r e l e a s e ] ; / / R e f C o u n t e r b = 1 N S S t r i n g * c = [ [ N S S t r i n g a l l o c ] i n i t ] ; / / R e f C o u n t e r c = 1 N S D i c t i o n a r y * d i c t = [ N S D i c t i o n a r y a l l o c ] i n i t W i t h O b j e c t : a r r a y f o r K e y : c ] ; / / R e f C o u n t e r a = 2 - R e f C o u n t e r b = 2 / / R e f C o u n t e r c = 1 - d i c t p o s s è d e u n e c o p i e d e s c l e f s / / R e f C o u n t e r a r r a y = 2 / / R e f C o u n t e r d i c t = 1 [ a r r a y r e l e a s e ] ; / / R e f C o u n t e r a = 1 - R e f C o u n t e r b = 1 / / R e f C o u n t e r c = 1 / / R e f C o u n t e r a r r a y = 1 / / R e f C o u n t e r d i c t = 1 [ d i c t r e l e a s e ] ; / / R e f C o u n t e r a = 0 - R e f C o u n t e r b = 0 / / R e f C o u n t e r c = 1 / / R e f C o u n t e r a r r a y = 0 / / R e f C o u n t e r d i c t = 0 [ c r e l e a s e ] ;
de gérer les cas de transmissions de propriété, la création de constructeurs de commodités et libération de la mémoire occupée inutilement dans des processus de longue durée. Dans les applications graphiques (iOS ou Cocoa), un pool de libération est crée automatiquement dans la boucle d'évènement à chaque évènement (NSRunLoop) Dans les applications non graphiques, le pool doit être explicitement crée.
dans le temps On ajoute un objet dans le pool courant en lui envoyant le message autorelease À chaque appel de la méthode release du pool, un message release est envoyé à chacun des objets présents dans le pool. Si on appellé N fois la méthode autorelease sur un objet, il faudra appeler N fois la méthode release du pool.
e a s e P o o l * p o o l = [ N S A u t o r e l e a s e P o o l a l l o c ] i n i t ] ; N S S t r i n g * s t r i n g 1 = [ [ [ N S S t r i n g a l l o c ] i n i t W i t h F o r m a t : @ " S e l f : % p " , s e l f ] a u t o r e l e a s e ] ; / / R e f C o u n t e r s t r i n g 1 = 1 + a j o u t d a n s ' p o o l ' N S S t r i n g * s t r i n g 2 = [ N S S t r i n g s t r i n g W i t h F o r m a t : @ " S t r i n g 1 : % @ " , s t r i n g 1 ] ; / / C o n s t r u c t e u r d e c o m m o d i t é - > s t r i n g 2 e s t e n v o y é d a n s l e p o o l c o u r a n t / / L e p o o l c o u r a n t à c e n i v e a u e s t ' p o o l " / / R e f C o u n t e r s t r i n g 2 = 1 ; N S A u t o r e l e a s e P o o l * p o o l _ 2 = [ N S A u t o r e l e a s e P o o l a l l o c ] i n i t ] ; N S S A r r a y * a r r a y = [ [ [ N S A r r a y a l l o c ] i n i t W i t h O b j e c t s : s t r i n g 1 , s t r i n g 2 , n i l ] a u t o r e l e a s e ] ; [ p o o l r e l e a s e ] ;
i r e p e r d u e @ i n t e r f a c e C o p i e u r : N S O b j e c t { N S A r r a y * _ c h e m i n s _ a _ c o p i e r ; / / T r è s g r a n d N S S t r i n g * _ d e s t i n a t i o n ; } @ e n d / * . . * / f o r ( N S S t r i n g * c h e m i n i n _ c h e m i n s _ a _ c o p i e r ) { N S S t r i n g * _ n o u v e a u _ c h e m i n = [ _ d e s t i n a t i o n s t r i n g B y A p p e n d i n g P a t h C o m p o n e n t : c h e m i n ] ; / * L o n g u e o p é r a t i o n * / } / / B e a u c o u p m i e u x f o r ( N S S t r i n g * c h e m i n i n _ c h e m i n s _ a _ c o p i e r ) { N S A u t o r e l e a s e * p o o l = [ [ N S A u t o r e l e a s e P o o l a l l o c ] i n i t ] ; N S S t r i n g * _ n o u v e a u _ c h e m i n = [ _ d e s t i n a t i o n s t r i n g B y A p p e n d i n g P a t h C o m p o n e n t : c h e m i n ] ; / * L o n g u e o p é r a t i o n * / [ p o o l r e l e a s e ] ; }
the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an event. / / E n p s e u d o c o d e i n t U I A p p l i c a t i o n M a i n ( . . . ) { w h i l e ( ! s h o u l d Q u i t A p p l i c a t i o n ) { / * A t t e n t e d ' u n é v e n è m e n t * / U I E v e n t * e v e n t = [ s e l f t r e a t E v e n t ] ; N S A u t o r e l e a s e P o o l * m y P o o l = [ [ N S A u t o r e l e a s e P o o l a l l o c ] i n i t ] ; / * T r a i t e m e n t d ' u n é v e m e n t : - A c t i o n s u r u n b o u t o n - C o n n e x i o n e n t r a n t e - N o t i f i c a t i o n . . . . * / [ m y P o o l r e l e a s e ] ; } } Chaque thread possède sa propre boucle d'évènements.
n a é t é c r é e a v a n t d ' a p p e l e r l a m é t h o d e N S A u t o r e l e a s e P o o l * p o o l = [ [ N S A u t o r e l e a s e P o o l a l l o c ] i n i t ] ; - ( I B A c t i o n ) b u t t o n C l i c k e d : ( i d ) s e n d e r { N S S t r i n g * m e s s a g e = [ N S S t r i n g s t r i n g W i t h F o r m a t : @ " S e n d e r : % p " , s e n d e r ] ; / / m e s s a g e R e f C o u n t e r = 1 N S O b j e c t * o b j = [ [ [ N S O b j e c t ] a l l o c ] i n i t ] a u t o r e l e a s e ] ; / / A j o u t d e o b j a u b a s s i n - o b j R e f c o u n t e r = 1 } / / D è s l e r e t o u r d e l a m é t h o d e l ' é v è n e m e n t e s t t r a i t é e s t l e " b a s s i n e s t v i d a n g é " [ p o o l r e l e a s e ] ; / / E n v o i e u n m e s s a g e r e l e a s e à t o u s l e s é l é m e n t s d u b a s s i n / / o b j R e f c o u n t e r = 0 / / m e s s a g e R e f C o u n t e r = 0
a pas forcément besoin par la suite Utilisation d'une méthode de classe et non d'instance L'objet crée est ajouté dans le bassin de libération avant d'être retourné
r t W i t h R e d { r e t u r n [ [ [ T S h i r t a l l o c ] i n i t W i t h C o l o r : [ U I C o l o r r e d C o l o r ] ] a u t o r e l e a s e ] ; } Attention dans le cas d'une sous‑classe / / C l a s s e T S h i r t P e r s o n n a l i s é : T S h i r t + ( i d ) t s h i r t p e r s o n n a l i s e W i t h R e d { r e t u r n [ [ [ s e l f a l l o c ] i n i t W i t h C o l o r : [ U I C o l o r r e d C o l o r ] ] a u t o r e l e a s e ] ; } / / A p p e l à s e l f p e r m e t d e r é u t i l i s e r l e s c o n s t r u c t e u r s d e s c l a s s e s p a r e n t e s
m m e n t f a i r e ? @ i n t e r f a c e V u e P e r s o n n a l i s e e : U I V i e w { i d < U I t a b l e V i e w D e l e g a t e > _ d e l e g a t e ; } @ e n d / / C o m m e n t é c r i r e l e m u t a t e u r d e ' _ d e l e g a t e ' ?
m m e n t f a i r e ? @ i n t e r f a c e V u e P e r s o n n a l i s e e : U I V i e w { i d < U I t a b l e V i e w D e l e g a t e > _ d e l e g a t e ; } @ e n d @ i m p l e m e n t a t i o n V u e P e r s o n n a l i s e e - ( v o i d ) s e t D e l e g a t e : ( i d < U I t a b l e V i e w D e l e g a t e > ) d e l e g a t e { _ d e l e g a t e = d e l e g a t e } @ e n d
valeur sans "leak" / / C o m m e n t f a i r e ? @ i n t e r f a c e H T T P R e q u e s t : N S O b j e c t { N S M u t a b l e S t r i n g * _ b u f f } @ e n d / / C o m m e n t é c r i r e l e m u t a t e u r d e ' b u f f ' s a n s f u i t e m é m o i r e ?
valeur sans "leaks" / / C o m m e n t f a i r e ? @ i n t e r f a c e H T T P R e q u e s t : N S O b j e c t { N S M u t a b l e S t r i n g * _ b u f f } @ e n d / / C o m m e n t é c r i r e l e m u t a t e u r d e ' b u f f ' s a n s f u i t e m é m o i r e ? @ i m p l e m e n t a t i o n H T T P R e q u e s t - ( v o i d ) s e t B u f f : ( N S M u t a b l e S t r i n g * ) b u f f { [ b u f f r e t a i n ] ; / / O B L I G A T O I R E : s i b u f f = = _ b u f f [ _ b u f f r e l e a s e ] ; _ b u f f = b u f f ; } @ e n d
/ / C o m m e n t f a i r e ? @ i n t e r f a c e P e r s o n n e : N S O b j e c t { N S S t r i n g * _ n o m } @ e n d / / C o m m e n t é c r i r e l e m u t a t e u r d e ' b u f f ' s a n s f u i t e m é m o i r e ? @ i m p l e m e n t a t i o n P e r s o n n e - ( v o i d ) s e t N o m : ( N S S t r i n g * ) n o m { N S S t r i n g * c o p y = [ n o m c o p y ] ; / / O B L I G A T O I R E : s i n o m = = _ n o m c a r [ _ n o m r e l e a s e ] ; / / s i l e s o b j e t s o n t i m m u a b l e s , i l s u t i l i s e n t _ n o m = n o m ; / / g é n é r a l e m e n t d e s c o p i e s s u p e r f i c i e l l e s } @ e n d
possèdent chacun une référence forte l'un vers l'autre. / / E x e m p l e @ i n t e r f a c e A : N S O b j e c t { B * _ b ; } @ i m p l e m e n t a t i o n A - ( v o i d ) s e t B : ( B * ) b { [ b r e t a i n ] ; _ b r e l e a s e ] ; _ b = b ; } @ e n d @ i n t e r f a c e B : N S O b j e c t { A * _ a ; } - ( v o i d ) s e t A : ( A * ) a { [ a r e t a i n ] ; _ a r e l e a s e ] ; _ a = a ; } A * a = [ [ A a l l o c ] i n i t ] ; / / A R e f C o u n t e r = 1 B * b = [ [ B a l l o c ] i n i t ] ; / / B R e f C o u n t e r = 1 [ a s e t B : b ] ; / / B R e f C o u n t e r = 2 [ b s e t A : a ] ; / / A R e f C o u n t e r = 2 [ a r e l e a s e ] ; / / A R e f C o u n t e r = 1 B R e f C o u n t e r = 2 [ b r e l e a s e ] ; / / B R e f C o u n t e r = 1 A R e f C o u n t e r = 1 / / - > L e a k p o t e n t i e l
et accesseurs sur les variables d'instances Originairement : 1 déclaration de @property = 1 déclaration de @synthetize Depuis XCode 4.4 le front‑end LLVM, les déclaration de @synthetize sont automatiques
o d e 4 . 4 @ i n t e r f a c e P e r s o n n e : N S O b j e c t { N S S t r i n g * _ n o m ; N S S t r i n g * _ p r e n o m ; N S M u t a b l e A r r a y * _ e m a i l s ; P e r s o n n e * _ v o i s i n ; } @ p r o p e r t y ( c o p y ) N S S t r i n g * n o m ; @ p r o p e r t y ( c o p y ) N S S t r i n g * p r e n o m ; @ p r o p e r t y ( r e t a i n ) N S M u t a b l e A r r a y * e m a i l s ; @ p r o p e r t y ( a s s i g n ) P e r s o n n e * v o i s i n ; @ e n d @ i m p l e m e n t a t i o n P e r s o n n e @ s y n t h e t i z e n o m = _ n o m ; @ s y n t h e t i z e p r e n o m = _ p r e n o m ; @ s y n t h e t i z e e m a i l s = _ e m a i l s ; @ s y n t h e t i z e v o i s i n = _ v o i s i n ; @ e n d
o d e 4 . 4 @ i n t e r f a c e P e r s o n n e : N S O b j e c t { } @ p r o p e r t y ( c o p y ) N S S t r i n g * n o m ; @ p r o p e r t y ( c o p y ) N S S t r i n g * p r e n o m ; @ p r o p e r t y ( r e t a i n ) N S M u t a b l e A r r a y * e m a i l s ; @ p r o p e r t y ( a s s i g n ) P e r s o n n e * v o i s i n ; @ e n d @ i m p l e m e n t a t i o n P e r s o n n e / / C l a n g c r é e a u t o m a t i q u e m e n t u n e v a r i a b l e p r é f i x i é p a r " _ " ( u n d e r s c o r e ) / / s i a u c u n s y n t h e t i z e n e p r é c i s e l a m é t h o d e / / A T T E N T I O N : l e f r o n t - e n d G C C n e l e p e r m e t p a s @ e n d
assign : assignation sans transfert de propriété copy : assignation d'une copie de l'objet Le runtime implémentent les mêmes mutateurs que ceux vus précédemment
a c e P e r s o n : N S O b j e c t { N S S t r i n g * _ n a m e ; } @ p r o p e r t y N S S t r i n g * n a m e ; @ e n d / * . . . * / N S M u t a b l e S t r i n g * s o m e N a m e = [ N S M u t a b l e S t r i n g s t r i n g W i t h S t r i n g : @ " C h r i s " ] ; P e r s o n * p = [ [ [ P e r s o n a l l o c ] i n i t ] a u t o r e l e a s e ] ; p . n a m e = s o m e N a m e ; [ s o m e N a m e s e t S t r i n g : @ " D e b a j i t " ] ; Qu'attendrait t'on dans ce contexte ?
P e r s o n : N S O b j e c t { N S S t r i n g * _ n a m e ; } @ p r o p e r t y N S S t r i n g * n a m e ; @ e n d N S M u t a b l e S t r i n g * s o m e N a m e = [ N S M u t a b l e S t r i n g s t r i n g W i t h S t r i n g : @ " C h r i s " ] ; P e r s o n * p = [ [ [ P e r s o n a l l o c ] i n i t ] a u t o r e l e a s e ] ; p . n a m e = s o m e N a m e ; [ s o m e N a m e s e t S t r i n g : @ " D e b a j i t " ] ; / / Q u e v a u t p . n a m e s i l a p r o p e r t y e s t r e t a i n ? c o p y ? / / - > r e t a i n : p . n a m e = @ " D e b a j i t " / / - > c o p y : p . n a m e = @ " C h r i s " / / N S S t r i n g e s t i m m u a b l e - > e r r e u r d e s é m a n t i q u e Les types immuables doivent normalement utiliser des mutateurs avec référence sur copie.
garbage collector instauré sur Mac OS X 10.5 à partir de 10.7 Activer l'ARC = demander au compilateur d'écrire les messages retain, release et autorelease à votre place Inconvénients : pas d'action directe sur la gestion mémoire, non disponible sur les versions Mac < 10.7
les objets Interdiction d'envoyer retain, release et autorelease Le type de liaison entre objet (référence forte, faible, copie) se fait à la déclaration de la variable ou de la propriété.
par défaut si rien n'est spécifié. / / E x e m p l e N S M u t a b l e S t r i n g * A ; N S M u t a b l e S t r i n g * _ _ s t r o n g B ; / / A R C A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = A ; / / É q u i v a l e n t A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = [ A r e t a i n ] ; [ A r e l e a s e ] ; / * D i f f é r e n t e s o p é r a t i o n s a u c o u r s d e s q u e l l e s A e s t d é s a l l o u é * / B = n i l ; / / M i s à 0 q u a n d p l u s a u c u n e r é f é r e n c e f o r t e n ' e x i s t e s u r l ' o b j e t / / I c i , q u a n d B e s t d é s a l l o u é
à nil quand il n'existe plus de référence forte sur l'objet. / / E x e m p l e N S M u t a b l e S t r i n g * _ _ s t r o n g A ; N S M u t a b l e S t r i n g * _ _ w e a k B ; / / A R C A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = A ; / / É q u i v a l e n t A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = A ; / * D i f f é r e n t e s o p é r a t i o n s a u c o u r s d e s q u e l l e s A e s t d é s a l l o u é * / B = n i l ; / / M i s à 0 q u a n d p l u s a u c u n e r é f é r e n c e f o r t e n ' e x i s t e s u r l ' o b j e t / / I c i , q u a n d B e s t d é s a l l o u é
mis à nil une fois l'objet désalloué / / E x e m p l e N S M u t a b l e S t r i n g * _ _ s t r o n g A ; N S M u t a b l e S t r i n g * _ _ w e a k B ; / / A R C A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = A ; / / É q u i v a l e n t A = [ [ N S M u t a b l e S t r i n g a l l o c ] i n i t W i t h S t r i n g : @ " H e l l o " ] ; B = A ; / * D i f f é r e n t e s o p é r a t i o n s a u c o u r s d e s q u e l l e s A e s t d é s a l l o u é * / B O O L o k = ( B = = n i l ) ; / / B e s t u n " d a n g l i n g p o i n t e r "
* ) et qui est envoyé dans le bassin de libération en retour de fonction / / E x e m p l e s u r l e s N S E r r o r - ( B O O L ) p e r f o r m O p e r a t i o n W i t h E r r o r : ( N S E r r o r * _ _ a u t o r e l e a s i n g * ) e r r o r ;
les rêgles de gestion mémoire à la main : un appel à alloc provoque un appel à release - ( v o i d ) f o o { N S A r r a y * a r r a y = [ [ N S A r r a y a l l o c ] i n i t ] ; / / A R C r a j o u t e u n r e l e a s e i c i }
L'ancienne déclaration est correcte mais moins efficace / / B e a u c o u p m i e u x f o r ( N S S t r i n g * c h e m i n i n _ c h e m i n s _ a _ c o p i e r ) { @ a u t o r e l e a s e { N S S t r i n g * _ n o u v e a u = [ _ d e s t i n a t i o n s t r i n g B y A p p e n d i n g P a t h C o m p o n e n t : c h e m i n ] ; / * L o n g u e o p é r a t i o n * / } }
x e m p l e @ i n t e r f a c e A : N S O b j e c t @ p r o p e r t y ( s t r o n g ) B * b ; @ e n d @ i n t e r f a c e B : N S O b j e c t @ p r o p e r t y ( s t r o n g ) A * a ; @ e n d A * a = [ [ A a l l o c ] i n i t ] ; B * b = [ [ B a l l o c ] i n i t ] ; A . b = b ; B . a = a ; - - > L e a k p o t e n t i e l