sous C ++, j'ai une classe mutex code>, et j'utilise cette classe de style Raii pour vous assurer que le mutex est déverrouillé, quelle que soit la raison du retour de la méthode:
NSLock *_lock; // instance variable
- (void)myFunc {
Locker *locker = [[Locker alloc] init];
locker.lock = _lock;
return; // Whenever I like
}
4 Réponses :
Je dirais que les méthodes de classe tels que provoqueraient probablement l'arc d'autoriser la valeur de retour (voir Cet article ). Je pense que ce sera autoritéé à moins que le nom de la méthode commence par J'ai toujours pensé à Raii comme étant une chose C / C ++ où vous pouvez attribuer des objets statiquement. Mais je suppose que vous pouvez le faire de cette façon, tant que vous ferez bien sûr que les objets ne sont pas autorélichés. p> p> alloc code>,
nouveau code>,
init code>,
copie code>,
Mutablecopy CODE> (ou sauf si vous utilisez des macros spéciales pour forcer le compilateur à ne pas autoréliquement, La documentation de Clang Arc est jolie Bon . Un objet Auteledeled serait évidemment un problème étant donné que votre serrure ne serait pas déverrouillé tant que la piscine de l'autorelease n'est pas égouttée. P>
+1 a accepté, comme indiqué par @martinr dans les commentaires. J'ai modifié la mise en œuvre maintenant pour éviter de telles méthodes. Pouvez-vous penser à une raison pour laquelle cela ne fonctionnerait pas?
Cela me fait peur un peu, mais je ne peux vraiment penser à rien. L'objet doit être traité dès que la "version" insérée par l'ARC est appelée, qui devrait être lorsque la portée du casier * est excitée ...
Eh bien, je ne peux pas le tester pour le moment, car cela fait partie d'un grand nouveau morceau de fonctionnalité, mais une fois que c'est prêt, je vais lui donner un bon test et revenir avec les résultats.
Je vaut la peine de lire la section d'optimisation clang.llvm.org/docs/...
Si vous voulez des motifs RAII, vous devez utiliser Objective-C ++ et écrire des cours C ++ Raii. P>
ARC est peu susceptible de vous donner le résultat que vous voulez. L'objet peut être traité trop tard, si quelque chose le cause d'être autorété. L'objet peut être traité trop tôt, si l'optimiseur ARC décide que l'objet n'est plus utilisé. P>
C'est certainement une option; Mon application actuelle est à 100% de l'objectif-C ++ de toute façon, de sorte que ce ne serait pas un problème. Pensez-vous que ce serait plus résilient? Je l'ai testé avec succès (voir le GIST dans ma question), la mise en œuvre de l'objectif-C proposé apparaît i> bien fonctionner.
Better API: Utilisez un bloc:
NSLock *someLock = ...; performBlockWithLock(someLock, ^{ // your code here });
+1 Pas une mauvaise idée Rob. Comme le code de mon application est tout Objective-C ++, j'utilise My C ++ Raii-style MuTExlock CODE> à la place, pour garantir la distraction, quoi qu'il arrive.
Ne fais pas ça! J'ai récemment chassé des bugs pendant une journée ou donc jusqu'à ce que j'ai découvert Tima et que l'ordre des objets libérés via Arc est un peu aléatoire, un peu de temps après que la dernière référece disparaisse. Il semble que les pools de libération automobile sont peuplés un peu au hasard. L'ordre n'est pas préservé. C'est-à-dire un objet enfant référencé que par un autre objet a été distribué après son objet parent. J'ai fini par faire de la ressource manuelle DeinInit via des messages "destruct" auto-fabriqués et finira de manière proportionnellement de portage tout sauf de code de colle à C ++. Je suis désolé pour les gens qui devaient utiliser Swift. Fondamentalement, tous les problèmes que vous avez avec GC .... P>
Une chose qui se voit dans mon esprit est que
[casier-casierwithlock: _lock] code> pourrait renvoyer un objet Autorélied, qui pourrait ne pas être immédiatement distribué lorsqu'il est hors de portée (en fonction des optimisations effectuées par le compilateur Arc ).
@Martinr Même avec la mise en œuvre ci-dessus de
retour [[casier Alloc] initwithlock: verrouillage]; code>?
Oui (je viens de l'essayer), parce que vous l'enveloppez dans
[casier-casierwithlock: _lock] code>. Si vous appelez directement
casier * caser = [[[casier Alloc] initwithlock: _lock] code> dans
myfunc code> alors il sera libéré immédiatement.
@Martinr Que diriez-vous de
casier * casier = [[[casier Alloc] init]; caser.lock = _lock; code> et effectue la serrure dans le setter? (c'est-à-dire se débarrasser sur la méthode de commodité au niveau de la classe).
Je garderais
initwithlocker: _lock code> et exécutez la verrouillage de la méthode init, qui est bien symétrique avec le déverrouillage dans DealLoc. Si vous vous inquiétez de la "variable non utilisée" AVERTISSEMENT, vous pouvez ajouter
casier = nil code> à la fin du corps de la fonction.
@Martinr ouais, c'est un peu ce que j'essaie d'éviter; Il n'y a pas besoin de ce genre de classe de cours, sauf lorsque j'oublie de faire la chose cruciale. J'ai changé la mise en œuvre, que je pense est à la fois en terres et fait ce qu'elle devrait (à moins que je n'ai pas manqué autre chose).
Oui, ça va bien pour moi. Donc, la seule chose était le problème de l'autorelease, mais vous avez déjà une réponse pour cela (je devrais écrire des réponses au lieu de commentaires :-)
C'est une idée intelligente! Pourquoi les vérifications explicites pour non-NIL dans le setter?
@JOSHCASWELL C'est donc nous assurons que nous sommes sûrs de verrouiller et de déverrouiller lorsque nous avons été transmis une serrure ou effacez la serrure.
Je ne pense pas que vous en avez besoin, à moins que vous ne le pense plus lisible. Si votre ivar,
_lock code>, est
nil code> au début du setter,
déverrouiller code> ne fera rien, et de même après
_lock = verrouillage code>; Si
verrouillage code> était
nil code> -
[nil verrouillage]; code> est un non-op.
@Joshcaswell ouais qui est vrai en fait. Merci.