Подтвердить что ты не робот

Переопределение геттера в Свифте

У меня есть ситуация, когда мне нужно переопределить getter свойства.

Скажем, у нас есть:

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

Ничего особенного, я думаю.

Теперь, если я попытаюсь переопределить getter в производном классе:

public class MyDerivedClass: MyBaseClass {
    public var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

Я получаю ошибку компиляции: нельзя переопределить свойство mutable с именем "только для чтения".

Если я попытаюсь добавить установщик и переопределить его:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super.name = newValue
        }
    }
}

Я получаю сообщение об ошибке: Setter overriding var должен быть таким же доступным, как и объявляемое им переопределение.

И если я попробую следующее:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

Затем компилятор сбой...

Как я могу добиться переопределения только получателя?

4b9b3361

Ответ 1

Это работает для меня:

    public class MyBaseClass {
        private var _name: String = "Hi"
        public internal(set) var name: String {
            get {
                return self._name
            }
            set {
                self._name = newValue
            }
        }
    }

    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
                super._name = newValue
            }
        }
    }

    MyDerivedClass().name

ИЗМЕНИТЬ

Этот код работает для меня на игровой площадке, помещая его в файл Источники → SupportCode.swift

    public class MyBaseClass {
    private var _name: String = "Hi"
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

    }

    public class MyDerivedClass:MyBaseClass {
        override public var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
               // do nothing
            }
        }
       public override init() {

        }
    }

Это немного помеха, потому что я получаю то же предупреждение, что и internal(set) не может быть помещен перед переопределенной переменной подкласса. Это может быть ошибка. А также я обманываю, чтобы убедиться, что сеттер производного класса ничего не делает.

Более распространенное использование internal(set) или private(set) состоит в том, чтобы иметь такой код, который аналогичен этому в документации:

public class MyBaseClass {
    public private(set) var _name: String = "Hi"
    public var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           super._name = newValue
        }
    }
   public override init() {

    }
}

Здесь сеттер можно читать напрямую с помощью MyDerivedClass()._name, но его нельзя изменить, например. этот MyDerivedClass()._name = "Fred" приведет к ошибке, но MyDerivedClass().name = "Fred" будет в порядке.

Ответ 2

Проблема 1

MyBaseClass не компилирует, потому что:

  • у него есть сохраненное свойство (_name)
  • это сохраненное свойство не является необязательным, поэтому оно не может быть nil
  • для его заполнения нет инициализатора

Итак, прежде всего нам нужно добавить правильный инициализатор в MyBaseClass

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get { return self._name }
        set { self._name = newValue }
    }
    init(name : String){
        _name = name
    }
}

Проблема 2

Теперь мы можем объявить MyDerivedClass, который переопределяет вычисленное свойство:

  • нам нужно использовать магическое ключевое слово переопределить
  • нам нужно предоставить как setter, так и getter

Здесь код:

public class MyDerivedClass: MyBaseClass {
    public override var name: String {
        get { return "Derived - \(super.name)" }
        set { super.name = newValue }
    }
}

Test

Из моей игровой площадки:

let somethingWithAName = MyDerivedClass(name: "default name")
println(somethingWithAName.name) // > "Derived - default name"
somethingWithAName.name = "another name"
println(somethingWithAName.name) // > "Derived - another name"