Швидке програмування: геттер / сетер у збереженій власності


102

Як перезаписати сетер збереженої власності в Swift?

У Obj-C я можу перезаписати його сетер, але, схоже, Swift не задоволений тим, що getter / setters використовуються для зберігання майна.

Скажіть, у мене Cardклас із властивістю під назвою rank. Я не хочу, щоб клієнт присвоював йому недійсне значення, тому в target-C я можу перезаписати setRankйого, щоб він здійснив додаткову перевірку. Але, willSetсхоже, у Swift це не допомагає, оскільки newValueє постійним і не має сенсу призначати, rankтому що сеттер буде викликаний у циклі.


Ви знайшли спосіб зробити це? Мені потрібен такий функціонал сам ...
Mihai Fratu

Я знайшов це. Перевірте мою відповідь ...
Mihai Fratu

А як щодо didGet чи аналога?
fnc12

Відповіді:


107

Гаразд. Читаючи документацію щодо яблук на Swift, я виявив це :

Якщо ви присвоїте значення властивості в межах свого власного спостерігача didSet, нове значення, яке ви призначите, замінить те, що було тільки що встановлено.

Отже, все, що вам потрібно зробити, це:

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

А як щодо didGet чи аналога?
fnc12

Не впевнений, що я розумію ваше запитання. Чи можете ви бути більш конкретними, будь ласка?
Mihai Fratu

Мені потрібно викликати якийсь код, перш ніж отримувати. Мені вдалося виконати це в obj-c, але я не бачу, як це зробити у Swift. Єдине, що я бачу, - це використовувати два властивості: один - це загальнодоступний, а один - приватний, публічний посилається на мій код і повертає значення приватної власності. Ось чому я запитав про didGet
fnc12

Ви можете мати лише геттер для обчисленої власності. Наприкладvar rankTimesTwo: Int { get { return rank * 2 } }
Mihai Fratu

2
Працює як шарм! Остерігайтеся, щоб він не зателефонував під час встановлення об'єкта в init ()
Крістоф

35

Ви не можете змінити get/ змінити setзбережений ресурс, але ви можете використовувати спостерігачі власності willSet/ didSet:

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

Назви параметрів за замовчуванням є " newValueза" willSetта "" oldValueдля " didSet, або ви можете назвати їх самі як willSet(newTotalSteps).


Це працює. Але це не вирішує мою проблему, можливо, я не був достатньо зрозумілий у своєму первісному питанні.
bohanl

Скажіть, у мене Cardклас із властивістю під назвою rank. Я не хочу, щоб клієнт надавав йому ніякого значення, тому в target-C я можу перезаписати setRankйого, щоб він здійснив додаткову перевірку. Але, willSetсхоже, у Swift це не допомагає, оскільки newValueє постійним і не має сенсу призначати, rankтому що сеттер буде викликаний у циклі.
bohanl

2
Я не зовсім впевнений, що ви маєте на увазі, але чи не могли ви використати didSetдля перевірки rankпісля встановлення, а якщо не вдалося перевірити , скинути його на щось інше, наприклад oldValue?
Джозеф Марк

9

get and set призначені для обчислених властивостей (у них немає резервного сховища). (На мою думку, ключове слово 'var' тут заплутане)

  • willSet і didSet викликаються змінною екземпляра (Використовуйте didSet для зміни будь-яких змін)
  • встановити та отримати суто для обчислених властивостей

9

Якщо ви не хочете використовувати didSet, у якого проблема, що значення властивості тимчасово неправильне, слід обернути навколо нього обчислюване властивість.

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        if(newValue > 999) {
            _foo = 999
        } else {
            _foo = newValue
        }
    }
}

Або:

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        guard newValue <= 999 else {
            _foo = 999
            return
        }
        _foo = newValue
    }
}

Немає сенсу використовувати дві змінні.
Піюш

1
Для цього використовується лише одна властивість (змінна): fooце просто обчислений вираз _foo, не дозволяйте, щоб ключове слово "var" вас обманювало! Це означає, що є два записи, доступні з приватного простору імен, але це не має жодного стосунку до захищених / загальнодоступних і зберігає значення fooдійсних у будь-який час. Це, по суті, схема "перегляду". Проблема, яка виникає при переписуванні через didSet, крім того, що вона має термін недійсності, полягає в тому, що існує значний потенціал для нескінченного циклу, оскільки ви повторно вводите didSetобробник зсередини didSet.
Джим Дрісколл

-8

Спрощений приклад:

class Shape {
    var sideLength: Double {
    get {
        return self.sideLength
    }
    set {
        // Implement the setter here.
        self.sideLength = newValue
    }
    }
}

Повний приклад

Ознайомтеся з perimeterцим прикладом.

Уривок: Apple Inc. "Мова швидкого програмування". iBooks. https://itun.es/us/jEUH0.l

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
    get {
        return 3.0 * sideLength
    }
    set {
        sideLength = newValue / 3.0
    }
    }

    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength”

3
у цьому випадку perimeterвсе ще є обчисленою властивістю. Як перезаписати sideLength без введення обчисленої властивості?
bohanl

@bohanl Я додав спрощений приклад, використовуючи getіset
Майк Рападас

6
Ваш "повний приклад" показує обчислену властивість, а не збережену власність, а "спрощений приклад" не працює.
Калеб

Я стою виправлений. Це так, ніби абстракція @property (автоматично синтезовані геттери + сетери) в Objective-C не була відменена в Swift. Іронія ...
Майк Рападас

6
Ви "спрощеним прикладом" називаєте геттера всередині самого геттера. Inf петля ... крах.
jakenberg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.