Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gestion de la mémoire en Objective-C2.0

yageek
March 05, 2013

Gestion de la mémoire en Objective-C2.0

Une introduction détaillée à la gestion de la mémoire en Objective-C

yageek

March 05, 2013
Tweet

More Decks by yageek

Other Decks in Programming

Transcript

  1. Gestion de la mémoire en ObjectiveC‑2.0 HEINRICH Yannick @yageek Mars

    2013 http://blog.yageek.net/objc20‑gestion‑memoire
  2. Les bases Objective‑C : Langage C + paradigme objet L'allocation/désallocation

    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,...)
  3. Allocation Compteur de référence : désallocation de l'objet lorsque le

    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
  4. MAObject @ i m p l e m e n

    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
  5. - ( v o i d ) d e a

    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.
  6. Convention Toute fonction contenant alloc, copy ou commencant par new

    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
  7. #Exemple N S S t r i n g *

    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 }
  8. Propriétaires d'un objet Le ou les propriétaires d'un objet sont

    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.
  9. Exemple N S S t r i n g *

    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
  10. Construire et initialiser un objet Construction On se sert de

    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 ] ;
  11. Initialiser un objet Exemple : une classe Personne @ i

    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 ?
  12. Initialiser un objet Chaque classe doit avoir un initialiseur désigné,

    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
  13. Initialiser un objet Tous les autres initialiseurs doivent finir par

    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
  14. Pas d'appel aux accesseurs Appels aux accesseurs déconseillés (interdits ?)

    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
  15. Échec dans l'initialisation Lors de l'échec dans l'initialiseur : 1.

    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
  16. Exemple @ i m p l e m e n

    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 ] ; }
  17. Destruction d'une classe Toujours appeler [super dealloc] en dernier dans

    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 é }
  18. Remarque Cela ne sert à rien, sauf justification particulière, de

    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
  19. FAUX @ i n t e r f a c

    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
  20. Copie d'objet Implémentation du protocol NSCopying et de la méthode

    copyWithZone: appellée par copy L'argument NSZone est un héritage et n'est plus utilisé. Implémentation dépend de la sémantique voulue.
  21. Copie d'objet Les objets de bases du Frameworks présentent une

    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
  22. Copie d'un objet Copie d'un objet dont la représentation en

    mémoire ne change pas (immuable) = copie superficielle. Copie d'un objet mutable = copie profonde Copie mutable d'un objet immuable : utilisation de mutableCopyWithZone:
  23. Exemple avec NSString Objet immuable ne veut pas dire pointeur

    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 " ] ;
  24. En pratique / / U n e c o p

    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 ; }
  25. Collections d'objet Les collections d'objets ne constitue pas des bloc

    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
  26. Exemple N S S t r i n g *

    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 ] ;
  27. Autorelease pools Les pools ou bassins de libérations automatiques permettent

    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.
  28. Autorelease Il faut le voir comme un message release différé

    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.
  29. Exemple 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 ] ; 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 ] ;
  30. Libérer de la mémoire / / M é m o

    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 ] ; }
  31. Boucle d'évènements The Application Kit creates an autorelease pool on

    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.
  32. Exemple / / U n b a s s i

    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
  33. Constructeurs de commodités Permet de construire un objet dont on

    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é
  34. Exemple + ( i d ) t s h i

    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
  35. Mutateurs Respect de l'encapsulation des données Selon le type de

    variable, les mutateurs n'ont pas la même forme Important de comprendre ces formes.
  36. Types de mutateurs Assignation avec transfert de propriété (référence forte)

    Assignation sans transfert de propriété (référence faible) Assignation d'une copie de l'objet (référence forte sur nouvel objet)
  37. Référence faible Cas le plus trivial / / C o

    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 ' ?
  38. Référence faible Cas le plus trivial / / C o

    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
  39. Référence forte But : garder l'ancienne valeur + relâcher l'ancienne

    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 ?
  40. Référence forte But : garder l'ancienne valeur + relâcher l'ancienne

    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
  41. Référence sur copie Même problématique que la référence forte simple

    / / 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
  42. Cycles de retenues Il faut normalement éviter que deux objets

    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
  43. Les propriétés Rappels Permet de créer dynamiquement l'éxecution des mutateurs

    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
  44. Exemple / / A v a n t X C

    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
  45. Exemple / / A p r è s X C

    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
  46. Types de propriétés retain : assignation avec transfert de propriété

    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
  47. Attention types immuables @ i n t e r f

    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 ?
  48. @ i n t e r f 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 " ] ; / / 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.
  49. Introduction à l'ARC L'ARC n'est pas un ramasse‑miette. Remplace le

    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
  50. ARC et LLVM LLVM garde les concepts de propriétés sur

    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é.
  51. __strong Référence forte avec transfert de propriété. C'est la valeur

    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 é
  52. __weak Référence faible sans transfert de propriété et pointeur mis

    à 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 é
  53. __unsafe_unretained Équivalent à __weak sauf que le pointeur n'est pas

    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 "
  54. __autoreleasing Indique un objet passer par référence (de type id

    * ) 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 ;
  55. Attention à l'ARC L'ARC respecte de manière bête et méchante

    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 }
  56. @autorelease Les bassins de libération automatiques se déclarent avec @autorelease.

    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 * / } }
  57. ARC et @property assign ‑> __unsafe_unretained . copy ‑> __strong

    ownership + mutateurs de copie retain ‑> __strong strong ‑> __strong unsafe_unretained ‑> __unsafe_unretained weak ‑> __weak
  58. Cycles de retenues Même remarque que précédemment / / 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 @ 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
  59. Aller plus loin Transitioning to ARC Release Notes ‑ Apple

    documentation Advanced Memory Management Programming Guide ‑ Apple documentation Objective‑C Automatic Reference Counting LLVM doc