2012-02-26 3 views
0

Je suis en train d'apprendre l'objectif-c et la programmation d'une application iPad. Une chose que je continue à faire trébucher et à relire est la gestion de la mémoire. J'arrive là-bas ... lentement. Les règles de base telles que pour chaque alloc/retain vous devez avoir un release est utile. Cependant, on me élude chose relativement basique et je me demande si quelqu'un pourrait expliquer ...Comprendre la gestion de la mémoire dans ios

Prenez le code suivant ...

NSArray *myArray = [[NSArray alloc] init]; 
myArray = [someNSSet allObjects]; 

Ceci est relativement simple codage avant et nécessiterait une déclaration [myArray release].

Cependant, je continue à voir des exemples de (et en fait, j'ai largement utilisé les éléments suivants « raccourci » ...

NSArray *myArray = (NSArray *)[someNSSet allObjects]; 

Comment, pour autant que je comprends lorsque vous utilisez le vous ne avez pas besoin (NSString *) d'utiliser une déclaration [myArray release], mais je ne comprends pas pourquoi.

quelqu'un pourrait-il possible d'expliquer?

Répondre

1

Dans la première ligne:

NSArray *myArray = [[NSArray alloc] init] 

une certaine quantité de mémoire est allouée pour un tableau (en fait dans ce cas, il est absurde puisque la taille du tableau est 0. Gardez à l'esprit que NSArray est immuable!). La variable myArray contient l'adresse du premier octet de la zone de mémoire réservée.

Maintenant, dans la deuxième ligne, vous modifiez la valeur de myArray qui pointera maintenant sur le premier octet de la zone de mémoire où [someNSSet allObjects] est stocké. A ce moment vous ne savez plus où le tableau est stocké ce que vous avez créé dans la première ligne. Et ainsi vous avez une fuite.

La ligne:

NSArray *myArray = (NSArray *)[someNSSet allObjects]; 

est correcte, puisque vous ne réservez pas de mémoire à ce point. Si vous n'utilisez pas ARC, vous pouvez appeler retain afin de conserver le GC à l'écart du bloc de mémoire référencé. D'une autre manière, vous pourriez recevoir un BAD_EXEC lorsque le propriétaire de l'objet le libère et vous essayez d'y accéder par exemple: [myArray objectAtIndex: 0]

2
NSArray *myArray = [[NSArray alloc] init]; 
myArray = [someNSSet allObjects]; 

ce code fuit myArray parce que vous perdez la référence à NSArray que vous avez allouée sur la première ligne; vous n'avez pas besoin de alloc ici, car sur la deuxième ligne, vous attribuez une nouvelle valeur à myArray.

NSArray *myArray = (NSArray *)[someNSSet allObjects]; 

et cet exemple de code est parfaitement bien, vous assignons le résultat de [someNSSet allObjects] à myArray pointeur et vous ne possédez pas la valeur retournée, de sorte que vous n'avez pas besoin de se soucier de le relâcher.

Envisagez d'utiliser ARC (Automatic Retain Counting) pour votre projet. Avec ARC, le compilateur prend en charge le nombre de retenues, de sorte que vous n'avez pas à le faire. Il y a un refactoring qui va convertir un projet en cours.

+0

Pourquoi ne pas posséder la valeur retournée? Qui/quoi? –

+0

@BenThompson: Lorsque vous créez un objet (nouveau ou alloc, copy ou mutableCopy), il a un nombre de retenues de 1 et vous le possédez. Lorsque vous envoyez un message à un objet, son nombre de réceptions est incrémenté de 1 et vous le possédez également. Vous avez seulement besoin de libérer des objets que vous possédez. –

+1

@Ben: Il est fort probable que le pool autorelease soit le propriétaire de l'objet retourné par 'allObjects'. L'autre possibilité est l'objet set, mais cela ne se produirait réellement que si l'ensemble exposait simplement un objet qu'il possédait déjà, plutôt que de créer un nouveau tableau. À l'exception d'une compréhension de ce qui se passe en arrière-plan, cependant, vous ne devriez pas vous préoccuper de savoir à qui appartiennent les choses. Soit vous faites ou vous ne faites pas, et c'est tout ce que vous devez considérer. –

2

Comme vous l'avez dit, il y a une fuite dans le premier code que vous avez posté. Vous devez donc ajouter une version:

NSArray *myArray = [[NSArray alloc] init]; 
[myArray release]; 
myArray = [someNSSet allObjects]; 

En fait, lorsque vous obtenez un objet grâce à une méthode qui commence par alloc, new ou copy, vous possédez, et vous devez la libérer. C'est pourquoi, ici vous devriez libérer le tableau que vous avez obtenu en utilisant la méthode alloc. Cette convention permet de savoir facilement quand vous possédez des objets et quand vous ne les possédez pas. Alors rappelez-vous: alloc, new ou copy.

En ce qui concerne le second exemple, vous avez obtenu le tableau si une méthode qui ne commence pas par l'un des trois mots (alloc, new ou copy), de sorte que vous ne possédez pas l'objet, et vous n'êtes pas responsable de le libérer. En fait, le tableau que vous avez obtenu est un objet auto-libéré, ce qui signifie que même si son compte de retenue est actuellement de 1, il sera automatiquement libéré lorsque quelque chose appelé le pool autorelease est drainé.

Voici une référence sur Memory Management Rules.

+0

peut être mieux inverser la ligne 2 avec la ligne 3 dans votre code de réponse (ou utiliser autorelease au lieu de release) – meronix

+0

Le 'release' dans la ligne 2 est d'équilibrer le' alloc' dans la ligne 2, de sorte que l'ancienne valeur de 'myArray' ne fuit pas. Nous devons faire cela avant d'assigner une nouvelle valeur à 'myArray'. – sch

+0

oui, bien sûr, mais si vous le libérez, à la ligne 3, myArray n'existe plus, il n'est plus alloué et pourrait vous donner une erreur, et vous ne pourriez pas l'utiliser. vous devez équilibrer alloc avec release, et utiliser vos objets entre ces 2 lignes. ou pas? – meronix