Swift tem uma sintaxe de declaração de propriedade muito semelhante à de C #:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
No entanto, também possui willSet
e didSet
ações. Eles são chamados antes e depois que o setter é chamado, respectivamente. Qual é o propósito deles, considerando que você poderia ter o mesmo código dentro do setter?
get
&set
) consiste basicamente em ter uma propriedade calculada com base em outra propriedade, por exemplo, converter um rótulotext
em um anoInt
.didSet
&willSet
existem para dizer ... ei, esse valor foi definido, agora vamos fazer isso, por exemplo, Nosso dataSource foi atualizado ... então vamos recarregar o tableView para incluir novas linhas. Para outro exemplo ver a resposta de DFRI sobre como chamar os delegados emdidSet
Respostas:
O ponto parece ser que, às vezes, você precisa de uma propriedade com armazenamento automático e algum comportamento, por exemplo, para notificar outros objetos que a propriedade acabou de ser alterada. Quando tudo o que você tem é
get
/set
, você precisa de outro campo para armazenar o valor. ComwillSet
edidSet
, você pode executar uma ação quando o valor é modificado sem precisar de outro campo. Por exemplo, nesse exemplo:myProperty
imprime seu valor antigo e novo toda vez que é modificado. Com apenas getters e setters, eu precisaria disso:Assim,
willSet
edidSet
representam uma economia de um par de linhas, e menos ruído na lista de campos.fonte
willSet
edidSet
não são chamados quando você define a propriedade de dentro de um método init, como observa a Apple:willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
myArrayProperty.removeAtIndex(myIndex)
... Não é esperado.Meu entendimento é que set e get são para propriedades computadas (sem suporte de propriedades armazenadas )
se você for de um Objective-C, tenha em mente que as convenções de nomenclatura foram alteradas. No Swift, uma iVar ou variável de instância é denominada propriedade armazenada
Exemplo 1 (propriedade somente leitura) - com aviso:
Isso resultará em um aviso, pois resultará em uma chamada de função recursiva (o getter chama a si mesmo). O aviso neste caso é "Tentativa de modificar 'teste' dentro de seu próprio getter".
Exemplo 2. Leitura / gravação condicional - com aviso
Problema semelhante - você não pode fazer isso , pois está chamando recursivamente o setter. Além disso, observe que este código não irá reclamar de nenhum inicializador, pois não há propriedade armazenada para inicializar .
Exemplo 3. Propriedade Computada de Leitura / Gravação - com Armazenamento de Suporte
Aqui está um padrão que permite a configuração condicional de uma propriedade armazenada real
Nota Os dados reais são chamados _test (embora possam ser quaisquer dados ou combinação de dados). Observe também a necessidade de fornecer um valor inicial (como alternativa, você precisa usar um método init) porque _test é na verdade uma variável de instância
Exemplo 4. Usando vontade e definir
Aqui vemos willSet e didSet interceptando uma alteração em uma propriedade armazenada real. Isso é útil para enviar notificações, sincronização etc ... (veja o exemplo abaixo)
Exemplo 5. Exemplo concreto - container ViewController
Observe o uso de ambas as propriedades computadas e armazenadas. Eu usei uma propriedade computada para evitar definir o mesmo valor duas vezes (para evitar que coisas ruins aconteçam!); Eu usei o willSet e o didSet para encaminhar notificações para o viewControllers (consulte a documentação do UIViewController e informações sobre os contêineres do viewController)
Espero que isso ajude, e por favor alguém grite se eu cometi um erro em qualquer lugar aqui!
fonte
//I can't see a way to 'stop' the value being set to the same controller - hence the computed property
aviso desaparecer depois que eu usei emif let newViewController = _childVC {
vez deif (_childVC) {
get
, acho que você precisa adicionarif _childVC == nil { _childVC = something }
e depoisreturn _childVC
.Estes são chamados Observadores de Propriedade :
Trecho de: Apple Inc. “A linguagem de programação Swift”. iBooks. https://itun.es/ca/jEUH0.l
Eu suspeito que é para permitir coisas que tradicionalmente faríamos com o KVO , como ligação de dados com elementos da interface do usuário ou desencadear efeitos colaterais de alterar uma propriedade, desencadear um processo de sincronização, processamento em segundo plano, etc.
fonte
fonte
Você também pode usar o
didSet
para definir a variável com um valor diferente. Isso não faz com que o observador seja chamado novamente, conforme indicado no guia Propriedades . Por exemplo, é útil quando você deseja limitar o valor conforme abaixo:fonte
As muitas respostas existentes bem escritas cobrem bem a pergunta, mas mencionarei, em alguns detalhes, uma adição que acredito que vale a pena abordar.
Os observadores
willSet
edidSet
property podem ser usados para chamar delegados, por exemplo, para propriedades de classe que são sempre atualizadas apenas pela interação do usuário, mas onde você deseja evitar chamar o delegado na inicialização do objeto.Vou citar o comentário votado por Klaas na resposta aceita:
Isso é bastante interessante, pois significa, por exemplo, que a
didSet
propriedade é uma boa opção de ponto de ativação para delegar retornos de chamada e funções, para suas próprias classes personalizadas.Como exemplo, considere algum objeto de controle de usuário personalizado, com alguma propriedade-chave
value
(por exemplo, posição no controle de classificação), implementada como uma subclasse deUIView
:Depois das quais suas funções delegadas podem ser usadas, digamos, em algum controlador de exibição para observar as principais alterações no modelo
CustomViewController
, assim como você usaria as funções delegadas inerentesUITextFieldDelegate
aosUITextField
objetos for (por exemplotextFieldDidEndEditing(...)
).Para este exemplo simples, use um retorno de chamada delegado da
didSet
propriedade da classevalue
para informar ao controlador de exibição que uma de suas saídas teve atualização de modelo associada:Aqui, a
value
propriedade foi encapsulada, mas geralmente: em situações como estas, tenha cuidado para não atualizar avalue
propriedade docustomUserControl
objeto no escopo da função de delegado associada (aquididChangeValue()
:) no controlador de exibição, ou você terminará com recursão infinita.fonte
E observe que
willSet
precisa de um nome de parâmetro para contornar, por outro lado,didSet
não.fonte
Às vezes, o getter e o setter são pesados demais para serem implementados apenas para observar as mudanças apropriadas nos valores. Geralmente, isso requer manipulação variável temporária extra e verificações extras, e você deve evitar até mesmo esse trabalho minúsculo se escrever centenas de getters e setters. Esses animais são para a situação.
fonte
willSet
edidSet
versus código setter equivalente? Parece uma afirmação ousada.Na sua própria classe (base),
willSet
edidSet
é bastante redundante , pois você pode definir uma propriedade calculada (por exemplo, métodos get e set) que acessa ae_propertyVariable
faz a pré e pós-prosessing desejada .Se, no entanto , você substituir uma classe em que a propriedade já está definida , em seguida, o
willSet
edidSet
são úteis e não redundante!fonte
Uma coisa
didSet
realmente útil é quando você usa tomadas para adicionar configurações adicionais.fonte
Eu não sei C #, mas com um pouco de adivinhação, acho que entendo o que
faz. Parece muito semelhante ao que você tem no Swift, mas não é o mesmo: no Swift você não tem o
getFoo
esetFoo
. Essa não é uma pequena diferença: significa que você não tem nenhum armazenamento subjacente pelo seu valor.Swift possui propriedades armazenadas e computadas.
Uma propriedade computada possui
get
e pode terset
(se for gravável). Mas o código no getter e setter, se eles realmente precisam armazenar alguns dados, deve fazê-lo em outra propriedades. Não há armazenamento de backup.Uma propriedade armazenada, por outro lado, possui armazenamento de backup. Mas não tem
get
eset
. Em vez disso, possuiwillSet
edidSet
pode ser usado para observar alterações variáveis e, eventualmente, desencadear efeitos colaterais e / ou modificar o valor armazenado. Você não temwillSet
edidSet
para propriedades calculadas e não precisa delas porque, para propriedades calculadas, é possível usar o códigoset
para controlar as alterações.fonte
getFoo
esetFoo
são espaços reservados simples para o que você deseja que os getters e setters façam. C # também não precisa deles. (I fez perder alguns sutilezas sintáticas como eu pedi antes que eu tivesse acesso ao compilador.)