objective-c - property - swift getter and setter example




Propriedades de variáveis somente leitura e não calculadas no Swift (3)

Estou tentando descobrir algo com a nova linguagem Apple Swift. Digamos que eu costumava fazer algo parecido com o seguinte em Objective-C. Eu tenho readonly propriedades e eles não podem ser alterados individualmente. No entanto, usando um método específico, as propriedades são alteradas de maneira lógica.

Eu tomo o seguinte exemplo, um relógio muito simples. Eu escreveria isso em Objective-C.

@interface Clock : NSObject

@property (readonly) NSUInteger hours;
@property (readonly) NSUInteger minutes;
@property (readonly) NSUInteger seconds;

- (void)incrementSeconds;

@end

@implementation Clock

- (void)incrementSeconds {
     _seconds++;

     if (_seconds == 60) {
        _seconds = 0;
        _minutes++;

         if (_minutes == 60) {
            _minutes = 0;
            _hours++;
        }
    }
}

@end

Para um propósito específico, não podemos tocar os segundos, minutos e horas diretamente, e só é permitido incrementar segundo a segundo usando um método. Somente esse método poderia alterar os valores usando o truque das variáveis ​​da instância.

Como não existem coisas assim em Swift, estou tentando encontrar um equivalente. Se eu fizer isso:

class Clock : NSObject {

    var hours:   UInt = 0
    var minutes: UInt = 0
    var seconds: UInt = 0

    func incrementSeconds() {

        self.seconds++

        if self.seconds == 60 {

            self.seconds = 0
            self.minutes++

            if self.minutes == 60 {

                self.minutes = 0
                self.hours++
            }
        }
    }
}

Isso funcionaria, mas qualquer um poderia alterar diretamente as propriedades.

Talvez eu já tenha um projeto ruim em Objective-C e é por isso que o potencial novo equivalente do Swift não está fazendo sentido. Se não e se alguém tiver uma resposta, eu ficaria muito grato;)

Talvez os futuros Mecanismos de Controle de Acesso prometidos pela Apple sejam a resposta?

Obrigado!


Basta prefixar a declaração de propriedade com private(set) , assim:

public private(set) var hours:   UInt = 0
public private(set) var minutes: UInt = 0
public private(set) var seconds: UInt = 0

private mantém o local em um arquivo de origem, enquanto internal mantém local para o módulo / projeto.

private(set) cria uma propriedade read-only , enquanto private define ambos, set e get to private.


Como não há controles de acesso (o que significa que você não pode fazer um contrato de acesso que difira dependendo de quem é o chamador), aqui está o que eu faria por agora:

class Clock {
    struct Counter {
        var hours = 0;
        var minutes = 0;
        var seconds = 0;
        mutating func inc () {
            if ++seconds >= 60 {
                seconds = 0
                if ++minutes >= 60 {
                    minutes = 0
                    ++hours
                }
            }
        }
    }
    var counter = Counter()
    var hours : Int { return counter.hours }
    var minutes : Int { return counter.minutes }
    var seconds : Int { return counter.seconds }
    func incrementTime () { self.counter.inc() }
}

Isso apenas acrescenta um nível de indireção, por assim dizer, para direcionar o acesso ao contador; outra classe pode fazer um relógio e acessar seu contador diretamente. Mas a ideia - ou seja, o contrato que estamos tentando fazer - é que outra classe deve usar apenas as propriedades e métodos de alto nível do Clock. Não podemos impor esse contrato, mas na verdade era praticamente impossível aplicar em Objective-C também.


Na verdade, o controle de acesso (que ainda não existe no Swift) não é tão imposto quanto você pode pensar no Objetivo C. As pessoas podem modificar suas variáveis ​​de leitura diretamente, se elas realmente quiserem. Eles simplesmente não fazem isso com a interface pública da classe.

Você pode fazer algo similar no Swift (recortar e colar do seu código, além de algumas modificações, eu não testei):

class Clock : NSObject {

    var _hours:   UInt = 0
    var _minutes: UInt = 0
    var _seconds: UInt = 0

    var hours: UInt {
    get {
      return _hours
    }
    }

    var minutes: UInt {
    get {
      return _minutes
    }
    }

    var seconds: UInt  {
    get {
      return _seconds
    }
    }

    func incrementSeconds() {

        self._seconds++

        if self._seconds == 60 {

            self._seconds = 0
            self._minutes++

            if self._minutes == 60 {

                self._minutes = 0
                self._hours++
            }
        }
    }
}

que é o mesmo que você tem no Objective C, exceto que as propriedades armazenadas são visíveis na interface pública.

Em swift você também pode fazer algo mais interessante, o que você também pode fazer no Objective C, mas provavelmente é mais rápido (editado no navegador, eu não testei):

class Clock : NSObject {

    var hours: UInt = 0

    var minutes: UInt {
    didSet {
      hours += minutes / 60
      minutes %= 60
    }
    }

    var seconds: UInt  {
    didSet {
      minutes += seconds / 60
      seconds %= 60
    }
    }

    // you do not really need this any more
    func incrementSeconds() {
        seconds++
    }
}




properties