IBOutlet, RetainCount, Release HELP
cocoacola71
Membre
Bonjour,
Me voilà donc dans les test mémoires de mon appli, sachant que celle-ci est ma première application je me pose quelques questions:
- IBOutlet (ex NSTextField) vaut 9 si je fait un retainCount à l'ouverture de ma fenêtre, est-ce normal?
- Est-ce que je dois Release mes IBOutlet? Car quand ma fenêtre se ferme avec Release ils sont libérés, non?
- Lorsque j'utilise mes fenêtre et mon webview mon allocation augmente, mais ne réduit pas? Je suis donc sur la bonne piste en relâchant mes objets?
Merci d'avance...
Me voilà donc dans les test mémoires de mon appli, sachant que celle-ci est ma première application je me pose quelques questions:
- IBOutlet (ex NSTextField) vaut 9 si je fait un retainCount à l'ouverture de ma fenêtre, est-ce normal?
- Est-ce que je dois Release mes IBOutlet? Car quand ma fenêtre se ferme avec Release ils sont libérés, non?
- Lorsque j'utilise mes fenêtre et mon webview mon allocation augmente, mais ne réduit pas? Je suis donc sur la bonne piste en relâchant mes objets?
Merci d'avance...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
On m'a déjà suggéré ARC mais cela contournerai le problème, et je ne comprendrai pas ces problèmes de mémoire qui à ce que j'ai saisie sont présent sur Iphone et Ipad contrairement à ARC /crazy.gif' class='bbc_emoticon' alt=' ' />
Autant commencer sur de bonnes bases et profiter ensuite des biens fait de l'ARC.
C'est ma façon de croquer la /apple.gif' class='bbc_emoticon' alt='' />
[Edit] Cette réponse n'est pas valable sur Mac OS, désolé
2) Tous les IBOutlets doivent être remis à nil dans le viewDidUnload, pour que si tu reçois une alerte mémoire (car RAM un peu à l'étroit) et que les ViewControllers qui ne sont pas à l'écran (toujours instanciés, mais masqués par d'autres, etc) libèrent alors automatiquement leur UIView pour libérer un peu de RAM (c'est dans ce cas que viewDidUnload est appelé), que tes IBOutlets libèrent aussi ces objets
Du coup pour les IBOutlets, si tu les déclares comme conseillé par Apple en @property(retain), les 2 règles s'appliquent, donc il faut les remettre à nil à la fois dans dealloc et dans le viewDidUnload.
Je pense que cela va faire énormément de bien à la mémoire /smile.png' class='bbc_emoticon' alt=':)' />
Elles doivent être obligatoirement passées à nil dans le dealloc ? un release sur ces propriétés ne fonctionne pas ?
ARC est présent sur iOS à partir de la version 4.0 ! Et cela ne contourne pas les problèmes. Tu confonds probablement avec le Garbage Collector, un gouffre à performance en passe de devenir une piéce de musée depuis l'apparition d'ARC. Et qui n'existais pas pour iPhone et iPad, seulement sous OSX.
Pourquoi mettre à nil dans un dealloc ? Un release suffit puisque ton ivar n'existe plus après le [super dealloc]...
Oui tout à fait désolé pour la confusion! Donc ARC me permettrait de passé à coté de ces retain release ?
Et autre chose viewdidload correspond bien à awakefromnib sous MAC?
Car lorsque je met à nil mes objets cela me crée des exceptions.
Et dernière chose nil sera compris par SnowLeopard? Car j'ai eu plusieurs soucis lorsque j'avais initialisé mes NSString à nil (remplacé par @"")
Oups, je n'avais pas vu que c'était une question Mac, j'ai donc répondu pour iOS, désolé.
Oui, tu n'as plus besoin de t'en préoccuper. ARC analyse le code pour ajouter automatiquement les retain, release et autorelease là où il faut, de manière invisible et transparente. C'est parfait pour les débutants et les éternels novices comme moi !
Par contre lorsque j'active arc en enlevant tout retain et release il me rend l'erreur "-fobjc-arc is not supported with fragile avi" ??
J'ai lu que cela viendrait du debugger? LLDB serait requis?
Soyons précis dans le vocabulaire :
Je parle des propriétés, pas des variables d'instances. D'ailleurs je n'utilise que des propriétés, je ne déclare quasiment jamais de variables d'instances dans mon .h. (Que des propriétés dans mon .h ou dans l'extension de ma classe dans mon .m pour les privées)
Du coup quand je déclare une [font=courier new,courier,monospace]@property(retain) NSString* toto;[/font] je ne m'embête pas à déclarer une ivar [font=courier new,courier,monospace]toto[/font], et je n'utilise partout dans mon code que[font=courier new,courier,monospace] self.toto[/font]. Donc je met [font=courier new,courier,monospace]self.toto[/font] à [font=courier new,courier,monospace]nil[/font] pour la relâcher.
Quand je lis (@Kixxx) "faire un release sur ces propriétés" ça me fait peur, car par cela stricto-sensu je comprend "faire un [font=courier new,courier,monospace][self.toto release][/font]" ce qu'il ne faut évidemment surtout pas faire (pas de release sur une propriété, une propriété gère elle-même les retain/release sur la backing variable qu'elle gère derrière !).
Peut-être voulais-tu sous-entendre "faire un release sur la variable d'instance associée à la propriété", donc "faire un [font=courier new,courier,monospace][toto release][/font]", et là ok, dans ce cas c'est correct.
Sauf que bon, faire un [font=courier new,courier,monospace][toto release][/font] ou un [font=courier new,courier,monospace]self.toto=nil[/font] c'est équivalent (à une vache près), et que moi explicitement je n'ai pas de variable d'instance "[font=courier new,courier,monospace]toto[/font]" de déclarée, juste une propriété "[font=courier new,courier,monospace]toto[/font]", (là est la nuance).
Alors certes je sais que [font=courier new,courier,monospace]@syntesize toto[/font] va me créer tout seul une variable d'instance du même nom que la propriété, mais au final pourquoi s'embêter ? J'ai masqué jusque là l'existence même de la variable d'instance que je n'utilise nulle part ailleurs dans mon code (j'aurais pu écrire [font=courier new,courier,monospace]@syntesize toto = plouf[/font] mon code continuerai à compiler) donc pourquoi l'utiliser juste à cet endroit ? Au risque que ça ne compile plus si je précise un autre nom pour la variable d'instance associée à ma propriété ?
Comme je n'utilise que des propriétés, si on manipule toujours les propriétés directement (sans se soucier de la variable d'instance automatiquement synthétisée par le compilateur pour nous, ce qui est préférable pour simplifier grandement la gestion de la mémoire plutôt que de la faire nous-même sur les variables d'instance), autant le faire jusqu'au bout. Autant utiliser le principe d'abstraction jusqu'au bout.
L'utilisation des property juste pour se simplifier la gestion mémoire est une mauvaise pratique à mon goût. Y'a ARC pour ça /tongue.png' class='bbc_emoticon' alt=':P' />
Oui et non. Je n'utilise pas ARC car j'ai toujours préféré gérer la mémoire moi même, et du coup les property sont un moyen simple de gérer les retain/release.
Bah pourquoi pas ? D'ailleurs Apple les utilise systématiquement dans ses exemples de code, même pour les variables d'instances "privées". Dans leur code tous les IBOutlet sont déclarées en tant que propriétés, et il n'y a rien de plus privé qu'un pointeur vers un objet graphique, c'est un détail d'implémentation qui n'a pas à être visible.
Au pire, si tu veux des propriétés privées, tu les mets dans une catégorie privée. Et puis de toute façon, maintenant la "norme" c'est le modern runtime, où on ne déclare carrément plus de variables d'instances.
D'ailleurs plus ça va plus dans les divers langages ça s'oriente comme ça aussi. en .NET également il existe cette notion de propriétés dont on n'a pas besoin de déclarer les backing variables (encore heureux, ça ferait le double de boulot, comme avant le Modern Runtime ObjC où on devait déclarer ivar + propriétés pour bien faire, (ou ivar + setters, encore plus chiant), alors que maintenant tout se fait tout seul...
Pour moi ça a été créé pour s'abstenir de devoir se taper à la mano l'écriture répétitive des getter/setter. Or, pour moi, un getter/setter c'est pour modifier ou accéder à une propriété depuis l'extérieur.
D'ailleurs il m'arrive souvent d'avoir une property en readonly mais dont je modifie la variable d'instance en interne, mais je veux qu'elle soit uniquement accessible en lecture depuis l'extérieur. Si on prend l'habitude de tout faire avec les property bah ça coince là et on est obligé de passer par l'ivar ce qui rend le code pas forcément super cohérent.
Dans l'absolu je trouve plus logique de passer par les ivars à l'intérieur d'une classe, surtout qu'elles sont automatiquement déclaré par le synthesize, et d'autant plus qu'avec ARC on évite justement de devoir se faire chier avec les release/retain.
Passer par les property pour les outlet me choque moins, car on peut partir d'un principe qu'effectivement on y accède depuis l'extérieur (depuis le nib) et qu'on set les ivar avec les valeurs des objets instanciés par le nib.
Ceci est valable pour MAC?
Car je sais que Snow léopard n'accepte pas nil, si je passe les IBOutlet et Property à nil cela aura des impacts au lancement de mon appli?
Non ça ne coince pas.
Tu peux très bien faire dans ton .h un
@property (readonly, copy) NSString *monString;
Qui expose ton string en lecture pour l'extérieur
Et en privé un :
@property (readwrite, copy) NSString *monString;
Pour ton usage interne.
Je trouve ça nickel.
Et oui les propriétés ont été créées pour se faciliter la vie, et pour t'éviter d'écrire les getter/setter à la main. Ca gagne du temps et des lignes de code. Mais du coup ça te permet justement aussi de t'abstraire de déclarer la variable d'instance... ce qui te gagne aussi du temps et des lignes de code.
Je veux dire si tu utilises les propriétés pour t'éviter d'écrire des lignes de code, en particulier d'écrire le setter et le getter, pourquoi ne pas aussi gagner des lignes de code à t'éviter de déclarer les variables d'instance ?
Et en plus, ça a le gros avantage d'éviter de risquer d'utiliser ta variable d'instance directement (même en interne) alors qu'il est toujours préférable d'utiliser les setter/getters quand il y en a (pour des raisons de cohérence, de gestion mémoire, de KVO, et de logique POO de ton archi pour mettre tout ce qu'il faut à jour)
Heu non je ne vois pas quel est le problème ? Tu la déclares en readonly dans le .h et en readwrite dans l'interface privée (dans l'extension de classe dans ton .m). Je fais ça très souvent, et là encore c'est également ce que préconise Apple
Dans l'absolu je trouve plus logique de passer par des propriétés partout pour être cohérent, et pour éviter d'oublier des actions (l'utilisation de la propriété qui appelle le setter/getter ne fait pas que la gestion mémoire, mais aussi la protection des resources dans le cas multithreading, ou la gestion du KVO, etc, ça se limite pas au retain/release), d'autant plus que depuis le Modern Runtime (donc depuis le début d'iOS) ces variables d'instance sont masquées à ton implémentation, donc tu peux totalement en faire abstraction (c'est aussi tout l'intérêt). Mixer les deux c'est se faire des noeuds au cerveau et risquer de zapper certains cas (MT/KVO entre autres)
Pourquoi mon Webview me prend de la mémoire à l'utilisation et ne la relâche pas??
Je prend un exemple incluant aussi NSTexfield.
.h
.m
Pour le webView, peut importe ce que je fait dessus la mémoire prend plusieurs MB sans les relacher.
Je trouve ca vraiment bizarre!!
J'ai hâte de passer sur IOS les doc sont beaucoup plus complète que MAC!
Ne jamais se baser sur le retainCount, il ne fournit jamais de valeur exploitable par le programmeur.
Le webKit est gourmand en mémoire (regarde Safari) pour des raisons difficiles à connaà®tre ( mise en cache des pages, des images, etc)
Je me suis fait un petit navigateur perso pour apprendre un peu le WebKit. Si j'ouvre une page web, navigue dans quelques liens, puis referme la fenêtre, la mémoire occupée reste à 60 meg. C'est normal et on ne peut pas y faire grand chose
/laugh.png' class='bbc_emoticon' alt='' />
Une bonne nouvelle pour moi (et une moyenne pour les utilisateurs lol).
Donc retainCount n'est pas fiable à 100% !! Je comprend aussi que l'écart entre le dev IOS et Mac OS n'est pas si identique que je le pensais...
Mouai, je suis pas totalement convaincu, mais pour mon prochain projet, je vais tenter de faire comme ça. En plus j'avais dis que je tenterais ARC. Je vais complètement changer mes habitudes de dev avec ce prochain projet ^^
Tout comme moi. L'intégralité des plantages (heureusement peu nombreux) de mes applications venait de dealloc intempestifs.
Depuis ARC, plus de plantage, moins de mémoire consommée et des performances supérieures! /thumbsup.gif' class='bbc_emoticon' alt='' />
Je suis bien évidemment sûr qu'un programmeur talentueux ferait bien mieux à base d'allocations et de libérations mais pour moi qui ne suis et ne serai jamais talentueux, c'est génial!
Passer systématiquement par les propriétés à l'intérieur même de la classe pour moi cela me semble aussi une aberration.