7 votes

Cocoa : test pour savoir si une NSString est immuable ou mutable ?

Cela produit un objet chaîne immuable :

NSString* myStringA = @"A";  //CORRECTED FROM: NSMutableString* myStringA = @"A";

Cela produit un objet chaîne mutable :

NSMutableString* myStringB = [NSMutableString stringWithString:@"B"];

Mais les deux objets sont signalés comme étant le même type d'objet, "NSCFString" :

NSLog(@"myStringA is type: %@, myStringB is type: %@", 
[myStringA class], [myStringB class]);

Alors, qu'est-ce qui distingue ces objets en interne, et comment puis-je tester cela, de sorte que je puisse facilement déterminer si une variable chaîne mystérieuse est immuable ou mutable avant de lui faire quelque chose de mal ?

13voto

Rob Napier Points 92148

Les documents comprennent une explication assez longue sur les raisons pour lesquelles Apple ne veut pas que vous fassiez cela et pourquoi ils ne le supportent pas explicitement dans les documents d'information. Réception d'objets mutables . Le résumé est :

Alors ne prenez pas de décision sur l'objet mutabilité des objets basée sur ce que l'introspection vous dit à propos d'un objet. Traitez objets comme mutables ou non en fonction de ce que l'on vous donne aux limites de l'API (c'est-à-dire en fonction du type de retour). Si vous avez besoin de marquer sans ambiguïté un objet comme mutable ou immuable lorsque vous le transmettez aux clients, passez cette information comme un avec l'objet.

Je trouve que leur exemple NSView est le plus facile à comprendre, et il illustre un problème de base de Cocoa. Vous avez un NSMutableArray appelé "elements" que vous voulez exposer comme un tableau, mais vous ne voulez pas que les appelants s'en mêlent. Vous avez plusieurs possibilités :

  1. Exposez votre NSMutableArray comme un NSArray.
  2. Toujours faire une copie non-mutable lorsque cela est demandé
  3. Stocke les éléments sous forme de NSArray et crée un nouveau tableau à chaque mutation.

J'ai fait tout ça à différents moments. #Le numéro 1 est de loin la solution la plus simple et la plus rapide. Elle est également dangereuse, puisque le tableau peut muter dans le dos de l'appelant. Mais Apple indique que c'est ce qu'ils font dans certains cas (notez l'avertissement pour -sous-regards dans NSView). Je peux confirmer que si les points 2 et 3 sont beaucoup plus sûrs, ils peuvent créer des problèmes de performance majeurs, ce qui est probablement la raison pour laquelle Apple a choisi de ne pas les utiliser sur les membres très accédés comme les -subviews.

Le résultat de tout ceci est que si vous utilisez le numéro 1, alors l'introspection vous induira en erreur. Vous avez un NSMutableArray coulé en NSArray, et l'introspection indiquera qu'il est mutable (l'introspection n'a aucun moyen de savoir le contraire). Mais vous ne devez pas le muter. Seul le contrôle de type à la compilation peut vous le dire, et c'est donc la seule chose à laquelle vous pouvez faire confiance.

La solution à ce problème serait une sorte de version immuable et rapide de la structure de données mutable. De cette façon, le numéro 2 pourrait être réalisé avec des performances décentes. Je peux imaginer des changements au cluster NSArray qui permettraient cela, mais cela n'existe pas dans Cocoa aujourd'hui (et pourrait avoir un impact sur les performances de NSArray dans le cas normal, ce qui en ferait un échec). Même si nous l'avions, il y a probablement trop de code qui repose sur le comportement actuel pour que l'introspection de la mutabilité soit un jour fiable.

4voto

Philippe Leybaert Points 62715

Il n'existe aucun moyen (documenté) de déterminer si une chaîne de caractères est mutable au moment de l'exécution ou non.

On pourrait s'attendre à ce que l'une des solutions suivantes fonctionne, mais aucune ne fonctionne :

[[s class] isKindOfClass:[NSMutableString class]]; // always returns false
[s isMemberOfClass:[NSMutableString class]]; // always returns false
[s respondsToSelector:@selector(appendString)]; // always returns true

Plus d'informations ici, bien que cela ne vous aide pas à résoudre le problème :

http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html

4voto

mfazekas Points 3024

Si vous voulez vérifier à des fins de débogage, le code suivant devrait fonctionner. La copie sur un objet immuable est elle-même, alors que c'est une vraie copie pour les types mutables, c'est sur cela que le code est basé. Notez que puisque vous appelez copy c'est lent, mais ça devrait être suffisant pour le débogage. Si vous souhaitez vérifier pour d'autres raisons que le débogage, consultez la réponse de Rob (et oubliez-la).

BOOL isMutable(id object)
{
   id copy = [object copy];
   BOOL copyIsADifferentObject = (copy != object);
   [copy release];
   return copyIsADifferentObject;
}

Avertissement : il n'y a bien sûr aucune garantie que copy soit équivalent à retain pour les types immuables. Vous pouvez être sûr que si isMutable renvoie NO alors il n'est pas mutable et la fonction devrait probablement être nommée canBeMutable . Dans le monde réel cependant, on peut supposer que les types immuables (NSString, NSArray) mettront en œuvre cette optimisation. Il existe un grand nombre de codes, y compris des éléments de base comme NSDictionary, qui s'attendent à une copie rapide à partir de types immuables.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X