Questão
Os documentos da Apple especificam que:
Os observadores willSet e didSet não são chamados quando uma propriedade é inicializada. Eles são chamados apenas quando o valor da propriedade é definido fora de um contexto de inicialização.
É possível forçar que estes sejam chamados durante a inicialização?
Por quê?
Digamos que eu tenho essa aula
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
Criei o método doStuff
, para tornar as chamadas de processamento mais concisas, mas prefiro apenas processar a propriedade dentro da didSet
função. Existe uma maneira de forçar isso a chamar durante a inicialização?
Atualizar
Decidi remover o intializer de conveniência da minha classe e forçá-lo a definir a propriedade após a inicialização. Isso me permite saber didSet
que sempre será chamado. Ainda não decidi se isso é melhor no geral, mas combina bem com minha situação.
defer
:convenience init(someProperty: AnyObject) { self.init() defer { self.someProperty = someProperty }
Respostas:
Crie um método próprio e use-o dentro do seu método init:
fonte
someProperty
como tipo:AnyObject!
(um opcional implicitamente desembrulhado), vocêself
pode inicializar completamente semsomeProperty
ser definido. Quando você liga,setSomeProperty(someProperty)
liga para o equivalente aself.setSomeProperty(someProperty)
. Normalmente você não seria capaz de fazer isso porqueself
não foi totalmente inicializado. ComosomeProperty
não requer inicialização e você está chamando um método dependenteself
, Swift sai do contexto de inicialização edidSet
será executado.init() { *HERE* }
terá o didSet chamado. Ótimo para esta pergunta, mas o uso de uma função secundária para definir alguns valores leva ao chamado didSet. Não é ótimo se você deseja reutilizar essa função de incubadora.Se você usar
defer
dentro de um inicializador , para atualizar as propriedades opcionais ou ainda atualizar as propriedades não-opcionais que você já tenha inicializado e depois de você ter chamado quaisquersuper.init()
métodos, então o seuwillSet
,didSet
, etc. será chamado. Acho isso mais conveniente do que implementar métodos separados, dos quais você precisa acompanhar as chamadas nos lugares certos.Por exemplo:
Produzirá:
fonte
defer
. Obrigado.Como uma variação da resposta de Oliver, você pode encerrar as linhas em um fechamento. Por exemplo:
Edit: A resposta de Brian Westphal é melhor imho. O bom dele é que ele indica a intenção.
fonte
Eu tive o mesmo problema e isso funciona para mim
fonte
Isso funciona se você fizer isso em uma subclasse
No
a
exemplo,didSet
não é acionado. Mas, porb
exemplo,didSet
é acionado, porque está na subclasse. Tem a ver com o queinitialization context
realmente significa, neste caso, osuperclass
que importava com issofonte
Embora isso não seja uma solução, uma maneira alternativa de fazer isso seria usar um construtor de classe:
fonte
someProperty
pois ela não terá dado um valor durante a inicialização.No caso específico em que você deseja chamar
willSet
oudidSet
entrarinit
para uma propriedade disponível em sua superclasse, você pode simplesmente atribuir sua super propriedade diretamente:Observe que a solução do Charlesismo com um fechamento sempre funcionaria também nesse caso. Então, minha solução é apenas uma alternativa.
fonte
Você pode resolvê-lo de maneira objetiva:
fonte
self.someProperty
sair do escopo de inicialização. Eu acredito que a mesma coisa poderia ser realizada fazendovar someProperty: AnyObject! = nil { didSet { ... } }
. Ainda assim, alguns podem apreciá-lo como um em torno do trabalho, graças a adição