10
votes

Convertir des objets auto-libérant à l'arc

OK, alors Apple a apporté l'arc à nous, ce qui est génial. Après avoir refactoring mon application à Arc presque tout fonctionne bien et il est beaucoup plus facile de développer et de maintenir.

Il n'y a qu'un problème que je ne peux toujours pas comprendre. P>

Mon programme de gestion de l'emploi montre Données différentes informations sur les propositions, les commandes et ainsi de suite dans leurs propres fenêtres. Donc, j'ai une classe spéciale où WindowControlers est attribué et initié avec Initwithwindownibname, puis la fenêtre est affichée avec ShowWindow: P>

- (void) proposalWindowWasClosed: (NSNotification *) notification
{
    [proposalWindowArray removeObjectIdenticalTo:[notification object]];
}


2 commentaires

Votre nouvelle méthode est essentiellement correcte. Avec ARC, vous devez conserver des références explicites aux objets pour que le compilateur puisse suivre correctement les appels de retenue / de libération. En fait, je pense que vous devriez éviter les astuces telles que appeler libérer dans les méthodes de rappel en général, que vous utilisiez ou non l'ARC.


@ROBKENIGER: Que suggérez-vous à la place? Imaginez que nous sommes dans le délégué de l'application, qui avance les actions reçues des contrôleurs d'affichage / de fenêtre et qu'il y a généralement beaucoup de contrôleurs différents impliqués. Créer une propriété pour chacun semble être inutile en désordre.


4 Réponses :


0
votes

Sans hacks, il n'y a pas de moyen élégant de garder un objet retenu autre que d'avoir une référence forte à celle-ci dans un autre objet. Par exemple, vous pouvez conserver un nsmutableArray nsmutablesset , ajoutez votre contrôleur là-bas et retirez-le dans WindowsWillClose: . Cela sera plus court que de poster une notification. Pour faire cette réutilisable, créez un windowControllerregistry singleton avec une matrice, où vous ajoutez des contrôleurs comme celui-ci, et qui écoutez automatiquement nswindowwillcellessotification et supprimez-les de son tableau en libérant ainsi Propriété.

En tant que solution de contournement rapide, vous pouvez effectuer Conserver / AutoRelease appels de fichier non arc : xxx


7 commentaires

Merci Hamstergene, ça va probablement fonctionner. Mais je cherche une solution peu plus élégante. Il doit y avoir une solution sans utiliser de conserver et de libérer. Sinon, je n'avais pas à passer à Arc.


Arc fait retenir / libérer une fonction de compilateur. Les appeler de cette façon est un comportement indéfini du compilateur sous Arc et pourrait faire n'importe quoi. Cela pourrait fuir, travailler, crash, parfois ou toujours. Par spécification, cela pourrait venir et frapper votre chien. Le compilateur a des optimisations qui suppriment des retenues et des versions inutiles telles qu'elles voit en forme. Arc parfois "Faskes" conserver et libérer. Votre approche peut déséquilibrer le système en fonction de la manière dont le compilateur optimise. Plus sur le comportement non défini: blog.regehr.org/archives/213 Plus sur les optimisations de l'arc: < un href = "http://bit.ly/friday-qa-2011-09-30" rel = "nOfollow noreferrer"> bit.ly/friday-qa-2011-09-30


@ROBNAPIER L'astuce est sale et ne doit pas être utilisée, mais pourquoi pensez-vous qu'il a un comportement indéfini? Arc n'annule pas l'envoi dynamique.


Parce que la spécification définit un tel programme comme "mal formé". Voir la section 7.1.1 de la spécification de l'arc. clang.llvm.org/docs/...


@Robnapier mal formé! = UB. Cela signifie qu'il ne doit pas compiler (et il ne sera pas si vous essayez d'essayer d'écrire @selector (conserver) dans n'importe quel fichier activé par l'arc, sans même l'envoyer), d'où l'utilisation du sélecteur-from-string pirater. Mais ce n'est pas UB d'invoquer ces méthodes de manière dynamique ou de code non arc du même projet.


Vous l'avez trompé en compilant en cachantt l'appel du compilateur. Mais si le compilateur élimine ou réorganise une conserverie, vous pourriez trop manger ici, car objc_retainatoreleaserAserturnvalue peut ne pas déterminer correctement ce qui se passe plus tard lorsqu'il intrusion du pointeur de retour de la pile (chèque de la discussion de Mikeash). Vous pouvez vous en tirer dans plusieurs cas et peut-être même dans tous les cas pour cette version du compilateur, mais vous êtes en dehors des comportements définis dans une unité de compilée compilée avec ARC. Dans une unité de compilation non-arc, le compilateur n'est pas autorisé à optimiser de cette façon.


@ROBNAPIER Je ne comprends toujours pas comment cette utilisation particulière de performalector pourrait éventuellement conduire à une dépassement, mais je vois le danger de cet astuce en général. Édité la réponse.



0
votes

Je pense que votre approche alternative devrait être correcte, mais je ne pense pas avoir besoin de la deuxième notification. Vous devriez être capable de faire:

- (void)windowWillClose:(NSNotification *)notification
{
    [proposalWindowArray removeObjectIdenticalTo:self];
}


1 commentaires

Malheureusement, la propositionWindowarray est une propriété privée de mon détail de classe spécialeWindowController qui gère l'alloué et l'initialisation des fenêtresContrôleurs comme la propositionWindowController. Donc, il n'ya aucun moyen d'accéder à la propriété privée de DétaillantsWindowController à propos de propositionWindowController.



10
votes

J'utiliserais probablement une approche déléguée plutôt que des notifications. Généralement, il est préférable d'avoir un objet externe qui garde une trace des fenêtres ouvertes. Des objets de retenue auto-attachés, comme votre ancien système, rompent les points de base de l'objet de l'objet et rendent difficile de trouver des choses (telles que «donnez-moi une liste de fenêtres ouvertes»). Les non-singletons qui ne sont que "flottants" là-bas revenaient souvent à vous mordre dans votre architecture (j'ai dû résoudre ce problème assez souvent).

Cela dit, parfois l'auto-propriété est au moins pratique et au pire non-The-The-of-the-World. Tellement propre. La seule différence est que vous devez le faire explicitement plutôt que de faire correspondre une fuite et une surexploitation (ce que fait votre ancien code).

Créer une propriété privée forte . Attribuer auto . Cela créera une boucle de retenue qui vous restera autour jusqu'à ce que vous définissez la propriété sur nil .


3 commentaires

Votre réponse est donc de conserver une gamme de sous-classes de contrôleur de fenêtre dans votre classe qui agit en tant que délégué et est appelée dans la méthode WindowWillClose du contrôleur de fenêtre?


Selon le système, je dispose souvent d'une fenêtre singleton singleton et de la laisser regarder nswindowwillcellessotification , mais parfois j'utilise la délégation comme vous le dites. Dépend de la manière dont il faut être intégré. Le WindowManager possède généralement toutes les fenêtresContrôleurs du système. C'est juste le design que je trouve habituellement que je me retrouve au moment où j'ai fini.


Rob: Après avoir fait beaucoup de recherches supplémentaires sur ce sujet (travaux d'espèce dans le cours "iPad et iPhone Development" de Paul Hegarty, trouvé dans iTunes U, que je peux très recomposer) J'accepte votre dernière réponse. Je l'ai fait maintenant TIHS TIHS (regarder le NswindowwillcLosotination ) et il semble être le moyen le plus élégant et raisonnable. Alors merci à tout le monde.



0
votes

J'ai eu ce même problème lorsque je suis passé à Arc. Votre solution fonctionne, mais vous faites trop compliqué. Vous pouvez essentiellement faire ce que vous faisiez avant d'avoir la fenêtre de la fenêtre elle-même lorsqu'elle se ferme, mais de manière compatible Arc.

La solution consiste simplement à créer une propriété de votre classe dans la classe elle-même. Pour votre exemple, en détailWindowController, vous ajouteriez la propriété suivante: p> xxx pré>

puis lorsque vous créez la fenêtre avec votre code ci-dessus, ajoutez une ligne comme si: P>

- (void)windowWillClose:(NSNotification *)notification
{
    // Let ARC tear this down and clean it up
    [self setTheWindowController:nil];
}


0 commentaires