Vérifier si une valeur est modifiée à l'aide de KVO dans Swift 3
Je voudrais savoir quand un ensemble de propriétés d'un objet Swift changements. Auparavant, j'avais mis en place cette en Objective-C, mais je vais avoir quelques difficultés à le convertir à Swift.
Mon précédent code Objective-C est:
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
if (![change[@"new"] isEqual:change[@"old"]])
[self edit];
}
Mon premier passage à une solution Swift était:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if change?[.newKey] != change?[.oldKey] { //Compiler: "Binary operator '!=' cannot be applied to two 'Any?' operands"
edit()
}
}
Cependant, le compilateur se plaint: "opérateur Binaire '!=' ne peut pas être appliqué à deux'?' opérandes"
Ma deuxième tentative:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? NSObject {
if let oldValue = change?[.oldKey] as? NSObject {
if !newValue.isEqual(oldValue) {
edit()
}
}
}
}
Mais, en pensant à cela, je ne pense pas que cela va fonctionner pour les primitives de swift des objets tels que des Int qui (je suppose) n'héritent pas de NSObject et à la différence de l'Objective-C version ne sera pas en boîte en NSNumber lorsqu'il est placé dans le changement dictionnaire.
Donc, la question est de savoir comment dois-je faire apparemment tâche facile de déterminer si une valeur est modifiée à l'aide du KVO dans Swift3?
Aussi, question bonus, comment puis-je faire usage de la 'de l'objet' variable? Il ne me laisse pas changer le nom et bien sûr, n'aime pas les variables avec les espaces.
Remarque il y a un Swift4 bug lorsque vous utilisez
.initial
. Pour une solution reportez-vous à hereOriginalL'auteur aepryus | 2016-10-19
Vous devez vous connecter pour publier un commentaire.
Ci-dessous est ma première Swift 3 réponse, mais Swift 4 simplifie le processus, éliminant la nécessité d'une coulée. Par exemple, si vous observez les
Int
propriété appeléebar
de lafoo
objet:Note, la fermeture de cette approche basée sur:
Vous sort d'avoir à mettre en œuvre un distinct
observeValue
méthode;Élimine le besoin pour la spécification d'un
context
, et en vérifiant que le contexte; etLa
change.newValue
etchange.oldValue
sont correctement typées, éliminant le besoin de manuel de la coulée. Si la propriété était une option, vous peut-être en toute sécurité les déballer, mais pas de conversion est nécessaire.La seule chose que vous devez faire attention est de s'assurer que votre fermeture à ne pas introduire une forte cycle de référence (d'où l'utilisation de
[weak self]
modèle).Ma première Swift 3 réponse est ci-dessous.
Vous dit:
En fait, si vous regardez ces valeurs, si les observés de la propriété est un
Int
, il vient par le dictionnaire comme unNSNumber
.Vous pouvez soit rester dans le
NSObject
monde:Ou de les utiliser comme
NSNumber
:Ou, je préfère, si c'était un
Int
valeur de certainsdynamic
propriété de certains Swift classe, je préfère aller de l'avant et de les jeter commeInt
:Vous avez demandé:
La
of
est l'étiquette externe pour ce paramètre (utilisé lorsque vous étiez à l'appel de cette méthode; dans ce cas, le système d'exploitation appelle cela pour nous, donc nous n'utilisons pas cette étiquette externe à court de la signature de la méthode). Leobject
est sur l'étiquette interne (utilisé dans la méthode elle-même). Swift a eu la capacité pour les externes et internes des étiquettes pour les paramètres pendant un certain temps, mais il n'a été véritablement embrassé dans l'API de Swift 3.En termes de lorsque vous utilisez cette
change
paramètre, vous l'utilisez si vous êtes en observant les propriétés de plus d'un objet, et si ces objets ont besoin d'un traitement différent sur le KVO, par exemple:Et puis:
En aparté, j'avais recommandons généralement à l'aide de la
context
, par exemple, ont unprivate var
:Puis ajouter l'observateur à l'aide de ce contexte:
Et puis avoir mon
observeValue
assurez-vous qu'il a été soncontext
, et pas celui établi par sa super-classe:Yep,
NSObject
technique est très bien. J'étais juste vous montrer des options. Par la voie, vous ne pouvez le faire KVO avec des types qui peuvent être représentés en Objective-C (par exemple, vous ne pouvez pas observerenum
; vous devez avoir leenum
avec les valeurs brutes, et de ne stocker le.rawValue
, pas laenum
, lui-même).Oh... j'ai compris le concept de la ofObject paramètre, mais l'objective-c opérateur ofObject a été converti 'de l'objet'. Apparemment, swift ignorer un mot avant le nom de la propriété, afin de permettre au développeur de donner le contexte de l'paramètre?
Oh, je pensais que vous posiez des questions sur la façon d'utiliser ce paramètre. Quand vous voyez
of object
, leof
est l'argument externe de l'étiquette (ce qui n'est pas vraiment applicable ici, car le système d'exploitation appeler cette, pas vous) et leobject
est sur l'étiquette interne (qui est ce que vous faites référence dans votre code à l'intérieur de cette méthode). La présente convention, à usage interne et externe, les noms d'argument, a été une partie de Swift pour un certain temps, mais Apple a enfin véritablement embrassé dans leur API refonte de Swift 3. Voir Argument étiquettes.Je suis en train de lire ici. Essayer de comprendre ce que la clé que je devrais utiliser quand je veux capturer la
initial
valeur. Il semble que je devrais faire quelque chose commeif let change = change?[.oldKey]
. Est ce que le droit? De sens que si ajouter des observateurs commeoptions: [.new,.initial]
...je peux les capturer à l'aide de.newKey
et.oldKey
OriginalL'auteur Rob
Ma deuxième tentative " contient un bug qui ne parviennent pas à détecter le moment où un changement de valeur ou de nul. La première tentative peut effectivement être fixé une fois on se rend compte que toutes les valeurs de "changement" sont NSObject:
ou une version plus concise si vous préférez:
OriginalL'auteur aepryus