Question
Les documents d'Apple spécifient que:
Les observateurs willSet et didSet ne sont pas appelés lors de la première initialisation d'une propriété. Ils sont uniquement appelés lorsque la valeur de la propriété est définie en dehors d'un contexte d'initialisation.
Est-il possible de forcer ces appels lors de l'initialisation?
Pourquoi?
Disons que j'ai cette classe
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
J'ai créé la méthode doStuff
pour rendre les appels de traitement plus concis, mais je préfère simplement traiter la propriété dans la didSet
fonction. Existe-t-il un moyen de forcer cet appel lors de l'initialisation?
Mettre à jour
J'ai décidé de supprimer l'intialiseur de commodité pour ma classe et de vous forcer à définir la propriété après l'initialisation. Cela me permet de savoir didSet
sera toujours appelé. Je n'ai pas décidé si c'est mieux dans l'ensemble, mais cela convient bien à ma situation.
defer
:convenience init(someProperty: AnyObject) { self.init() defer { self.someProperty = someProperty }
Réponses:
Créez une propre méthode set et utilisez-la dans votre méthode init:
la source
someProperty
tant que type:AnyObject!
(une option implicitement déballée), vous autorisez l'self
initialisation complète sanssomeProperty
être définie. Lorsque vous appelez,setSomeProperty(someProperty)
vous appelez un équivalent deself.setSomeProperty(someProperty)
. Normalement, vous ne pourrez pas le faire car ilself
n'a pas été complètement initialisé. PuisquesomeProperty
ne nécessite pas d'initialisation et que vous appelez une méthode dépendante deself
, Swift quitte le contexte d'initialisation etdidSet
s'exécute.init() { *HERE* }
aura appelé didSet. Idéal pour cette question, mais l'utilisation d'une fonction secondaire pour définir certaines valeurs conduit à l'appel de didSet. Pas génial si vous voulez réutiliser cette fonction de setter.Si vous utilisez l'
defer
intérieur d'un initialiseur , pour mettre à jour des propriétés facultatives ou pour mettre à jour des propriétés non facultatives que vous avez déjà initialisées et après avoir appelé dessuper.init()
méthodes, votrewillSet
,didSet
etc. sera appelée. Je trouve cela plus pratique que d'implémenter des méthodes distinctes que vous devez suivre pour appeler aux bons endroits.Par exemple:
Donnera:
la source
defer
. Merci.Comme variante de la réponse d'Oliver, vous pouvez envelopper les lignes dans une fermeture. Par exemple:
Edit: la réponse de Brian Westphal est à mon humble avis. La bonne chose à propos du sien est qu'il fait allusion à l'intention.
la source
J'ai eu le même problème et cela fonctionne pour moi
la source
Cela fonctionne si vous le faites dans une sous-classe
Par
a
exemple,didSet
n'est pas déclenché. Mais dans l'b
exemple,didSet
est déclenché, car il est dans la sous-classe. Il doit faire quelque chose avec ceinitialization context
qui signifie vraiment, dans ce cas,superclass
il s'en est occupéla source
Bien que ce ne soit pas une solution, une autre façon de procéder serait d'utiliser un constructeur de classe:
la source
someProperty
car il ne lui aura pas donné de valeur lors de l'initialisation.Dans le cas particulier où vous souhaitez invoquer
willSet
ou à l'didSet
intérieurinit
pour une propriété disponible dans votre superclasse, vous pouvez simplement assigner directement votre super propriété:Notez que la solution de Charlesisme avec une fermeture fonctionnerait toujours aussi dans ce cas. Ma solution n'est donc qu'une alternative.
la source
Vous pouvez le résoudre de manière obj-с:
la source
self.someProperty
vous quittez la portée d'initialisation. Je crois que la même chose pourrait être accomplie en faisantvar someProperty: AnyObject! = nil { didSet { ... } }
. Pourtant, certains pourraient l'apprécier comme solution de contournement, merci pour l'ajout