L'important, c'est qu'en général, vous utilisez quelque chose (plutôt que rien) et que tout ce que vous utilisez, être unique et privé pour votre usage.
Le principal écueil ici se passe quand vous avez une observation dans une de vos classes, et puis quelqu'un de votre sous-classes de la classe, et ils ajoutent une autre observation d'un même objet observé et le même chemin d'accès clé. Si votre originale observeValueForKeyPath:...
seulement la mise en œuvre vérifié keyPath
, ou observées object
, ou même les deux, qui pourrait ne pas être suffisante pour savoir que c'est votre observation appelé revenir. À l'aide d'un context
dont la valeur est unique et privée vous permet d'être beaucoup plus sûr que d'un appel à l' observeValueForKeyPath:...
est l'appel que vous attendez qu'elle soit.
Ce serait grave si, par exemple, vous avez enregistré uniquement pour didChange
des notifications, mais une sous-classe de registres pour le même objet et le chemin d'accès clé avec l' NSKeyValueObservingOptionPrior
option. Si vous n'avez pas de filtrage des appels d' observeValueForKeyPath:...
à l'aide d'un context
(ou pour vérifier le changement de dictionnaire), votre gestionnaire d'exécuter plusieurs fois, lorsque vous ne l'attendait à exécuter une fois. Il n'est pas difficile d'imaginer comment cela pourrait causer des problèmes.
Le modèle que j'utilise est:
static void * const MyClassKVOContext = (void*)&MyClassKVOContext;
Ce pointeur pointe vers son propre site, et que l'emplacement est unique (pas d'autres statique ou variable globale peut avoir cette adresse, ni aucune de segment de pile ou objet alloué jamais avoir cette adresse -- c'est assez forte, mais certes pas absolue, garantie), grâce à l'éditeur de liens. L' const
fait en sorte que le compilateur va nous avertir si nous avons jamais essayé d'écrire du code qui permettrait de modifier la valeur du pointeur, et enfin, static
fait privé de ce fichier, de sorte que personne en dehors de ce fichier peut obtenir une référence à elle (encore une fois, ce qui rend plus probable pour éviter les collisions).
Un modèle que je voudrais spécialement attention à l'encontre de l'aide est celui qui est apparu dans la question:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSString *action = (NSString*)context;
if([action isEqualToString:GMAP_ANNOTATION_SELECTED]) {
context
est déclarée void*
, ce qui signifie que c'est la garantie qui peut être faite à propos de ce qu'il est. Par moulage d'un NSString*
vous êtes à l'ouverture d'une grosse boîte de potentiel de méchanceté. Si quelqu'un arrive à avoir un enregistrement qui n'est pas utiliser un NSString*
de la context
paramètre, cette approche se bloquer lorsque vous passez la non-valeur de l'objet d' isEqualToString:
. Pointeur de l'égalité (ou alternativement intptr_t
ou uintptr_t
de l'égalité) sont la seule sécurité des chèques qui peuvent être utilisés avec un context
de la valeur.
À l'aide de self
comme context
est une approche commune. C'est mieux que rien, mais elle est beaucoup plus faible uniquing et de la vie privée, puisque d'autres objets (pour ne pas mentionner les sous-classes) ont accès à la valeur de self
et peut l'utiliser comme un context
(cause de l'ambiguïté), contrairement à l'approche que j'ai proposé ci-dessus.
Aussi rappelez-vous, ce n'est pas juste les sous-classes qui pourraient causer des pièges ici; Même si c'est sans doute l'un des rares motif, il n'y a rien que le fait de prévenir un autre objet de l'enregistrement de votre objet pour les nouveaux KVO observations.
Pour une meilleure lisibilité, vous pouvez également envelopper ceci dans une macro préprocesseur comme:
#define MyKVOContext(A) static void * const A = (void*)&A;