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

Переопределение хранимого имущества в Swift

Я заметил, что компилятор не позволит мне переопределить сохраненное свойство с другим сохраненным значением (что кажется странным):

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

Однако мне разрешено делать это с вычисленным свойством:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}

Почему мне не разрешено давать ему другое значение?

Почему переопределение с сохраненным свойством мерзость и выполнение его с помощью вычисления одного кошерного? Что, где они думают?

4b9b3361

Ответ 1

Почему я не могу просто дать ему другое значение?

Вам определенно разрешено присвоить наследуемому свойству другое значение. Вы можете сделать это, если вы инициализируете свойство в конструкторе, который принимает это начальное значение, и передаете другое значение из производного класса:

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)

Переопределение свойства - это не то же самое, что присвоение ему нового значения - это больше похоже на присвоение классу другого свойства. Фактически это то, что происходит при переопределении вычисляемого свойства: код, который вычисляет свойство в базовом классе, заменяется кодом, который вычисляет переопределение для этого свойства в производном классе.

Можно ли переопределить фактическое сохраненное свойство, то есть lightSaberColor который имеет другое поведение?

Помимо наблюдателей, хранимые свойства не имеют поведения, поэтому там нечего переопределять. Придать свойству другое значение можно через механизм, описанный выше. Это именно то, что пытается сделать пример в вопросе, с другим синтаксисом.

Ответ 2

Для меня ваш пример не работает в Swift 3.0.1.

Вошел на площадку этот код:

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}

Выдает ошибку во время компиляции в Xcode:

не может переопределить неизменное свойство 'let' lightsaberColor 'с помощью метода get' var '

Нет, вы не можете изменить тип хранимого свойства. Принцип подстановки Лискова вынуждает вас разрешить использовать подкласс в месте, где требуется суперкласс.

Но если вы измените его на var и, следовательно, добавите set в вычисляемое свойство, вы можете переопределить сохраненное свойство вычисляемым свойством того же типа.

class Jedi {
    var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
        set {
            // nothing, because only red is allowed
        }
    }
}

Это возможно, потому что имеет смысл переключиться с сохраненного свойства на вычисляемое свойство.

Но переопределять сохраненное свойство var с сохраненным свойством var не имеет смысла, потому что вы можете только изменить значение свойства.

Однако вы не можете переопределить сохраненное свойство с сохраненным свойством вообще.


Я бы не сказал, что ситхи являются джедаями: -P. Поэтому ясно, что это не может работать.

Ответ 3

Вероятно, вы захотите оценить другое свойство:

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}

Ответ 4

class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}

Ответ 5

Для Swift 4 из документации Apple:

Вы можете переопределить унаследованное свойство экземпляра или типа, чтобы предоставить свой собственный метод получения и установки для этого свойства, или добавить наблюдатели свойства, чтобы свойство переопределения могло наблюдать, когда изменяется значение базового свойства.

Ответ 6

В Swift это, к сожалению, невозможно сделать. Лучшая альтернатива заключается в следующем:

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}

Ответ 7

Вы также можете использовать функцию для переопределения. Это не прямой ответ, но может обогатить эту тему)

Класс А

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}

Класс Б: А

public func shouldDoSmth() -> Bool {
    return false
}

Ответ 8

У меня была та же проблема, чтобы установить константу для контроллера представления.

Поскольку я использую конструктор интерфейса для управления представлением, я не могу использовать init(), поэтому мой обходной путь был аналогичен другим ответам, за исключением того, что я использовал вычисляемую переменную только для чтения как для базовых, так и для унаследованных классов.

class Jedi {
    var type: String {
        get { return "Blue" }
    }
}

class Sith: Jedi {
    override var type: String {
        get { return "Red" }
    }
}