Swift somente leitura externa, propriedade interna de leitura e escrita

103

Em Swift, qual é a maneira convencional de definir o padrão comum onde uma propriedade deve ser somente leitura externamente, mas modificável internamente pela classe (e subclasses) que a possuem.

Em Objective-C, existem as seguintes opções:

  • Declare a propriedade como somente leitura na interface e use uma extensão de classe para acessar a propriedade internamente. Este é o acesso baseado em mensagem, portanto, funciona bem com KVO, atomicidade, etc.
  • Declare a propriedade como somente leitura na interface, mas acesse o ivar de apoio internamente. Como o acesso padrão para um ivar é protegido, isso funciona bem em uma hierarquia de classes, onde as subclasses também podem modificar o valor, mas o campo é somente leitura.

Em Java, a convenção é:

  • Declare um campo protegido e implemente um getter (método) público somente leitura.

Qual é o idioma do Swift?

Jasper Blues
fonte

Respostas:

219

Dada uma propriedade de classe, você pode especificar um nível de acesso diferente prefixando a declaração de propriedade com o modificador de acesso seguido por getou setentre parênteses. Por exemplo, uma propriedade de classe com um getter público e um setter privado será declarada como:

private(set) public var readonlyProperty: Int

Leitura sugerida: Getters e Setters

As considerações de Martin sobre o nível de acessibilidade ainda são válidas - ou seja, não há protectedmodificador, internalrestringe o acesso apenas ao módulo, apenas privateao arquivo atual epublic sem restrições.

Swift 3 notas

2 novos modificadores de acesso, fileprivatee openforam adicionados ao idioma, enquanto privatee publicforam ligeiramente modificados:

  • openaplica-se à classe e aos membros da classe apenas: é usado para permitir que uma classe seja subclassificada ou um membro seja sobrescrito fora do módulo onde estão definidos. publicem vez disso, torna a classe ou o membro acessível publicamente, mas não herdável ou substituível

  • privateagora torna um membro visível e acessível apenas a partir da declaração anexa, enquanto fileprivatepara todo o arquivo onde ele está contido

Mais detalhes aqui .

Antonio
fonte
Agradável! (Tomei a liberdade de adicionar a varpalavra-chave que faltava para fazer a compilação.)
Martin R
oh, muito obrigado :) Eu geralmente copio do playground e colo, mas desta vez provavelmente fiz errado.
Antonio
10
Observe que, a partir de janeiro de 2015, esta sintaxe não está totalmente correta se a classe externa não for public- deveria serinternal ou nada (o que é padronizado para qualquer classe - publicou internal) - isto éprivate(set) var readonlyProperty: Int
Grimxn
1
Bem, a sintaxe está correta levando em consideração que logo antes do código eu escrevi uma propriedade de classe com um getter público e um setter privado - é apenas um exemplo. Mas sim, os modificadores de acesso para propriedades devem ser "compatíveis" com o modificador de acesso de classe / estrutura.
Antonio
Em relação ao último parágrafo, acho que isso mudou desde que a resposta foi escrita, mas privateagora se restringe à declaração atual (não ao arquivo) e fileprivateestá disponível para restringir ao arquivo atual. Também publictem algumas restrições e não opené necessário para nenhuma restrição. Detalhes aqui .
Nigel B. Peck
2

De acordo com @Antonio, podemos usar uma única propriedade para acessar como o readOnlyvalor da propriedade pública e readWriteprivada. Abaixo está minha ilustração:

class MyClass {

    private(set) public var publicReadOnly: Int = 10

    //as below, we can modify the value within same class which is private access
    func increment() {
        publicReadOnly += 1
    }

    func decrement() {
        publicReadOnly -= 1
    }
}

let object = MyClass()
print("Initial  valule: \(object.publicReadOnly)")

//For below line we get the compile error saying : "Left side of mutating operator isn't mutable: 'publicReadOnly' setter is inaccessible"
//object.publicReadOnly += 1

object.increment()
print("After increment method call: \(object.publicReadOnly)")

object.decrement()
print("After decrement method call: \(object.publicReadOnly)")

E aqui está a saída:

  Initial  valule: 10
  After increment method call: 11
  After decrement method call: 10
Santosh
fonte