Substituindo a propriedade da superclass por um tipo diferente em Swift

No Swift, alguém pode explicar como replace uma propriedade em uma superclass com outro object subclass da propriedade original?

Veja este exemplo simples:

class Chassis {} class RacingChassis : Chassis {} class Car { let chassis = Chassis() } class RaceCar: Car { override let chassis = RacingChassis() //Error here } 

Isso dá o erro:

 Cannot override with a stored property 'chassis' 

Se eu tiver o chassi como ‘var’, recebo o erro:

 Cannot override mutable property 'chassis' of type 'Chassis' with covariant type 'RacingChassis' 

A única coisa que eu consegui encontrar no guia em “Overriding Properties” indica que nós temos que sobrescrever o getter e setter, o que pode funcionar para mudar o valor da propriedade (se for ‘var’), mas que tal mudar a class de propriedade? ?

O Swift não permite alterar o tipo de class de quaisquer variables ​​ou propriedades. Em vez disso, você pode criar uma variável extra na subclass que lida com o novo tipo de class:

 class Chassis {} class RacingChassis : Chassis {} class Car { var chassis = Chassis() } class RaceCar: Car { var racingChassis = RacingChassis() override var chassis: Chassis { get { return racingChassis } set { if newValue is RacingChassis { racingChassis = newValue as RacingChassis } else { println("incorrect chassis type for racecar") } } } } 

Parece que não é possível declarar uma propriedade com a syntax let e sobrepô-la com var em sua subclass ou vice-versa, o que pode ser porque a implementação da superclass pode não estar esperando que essa propriedade seja alterada uma vez inicializada. Portanto, neste caso, a propriedade também precisa ser declarada com ‘var’ na superclass para corresponder à subclass (como mostrado no snippet acima). Se não é possível alterar o código-fonte na superclass, provavelmente é melhor destruir o RaceCar atual e criar um novo RaceCar toda vez que o chassi precisar ser mutado.

Isso parece funcionar

 class Chassis { func description() -> String { return "Chassis" } } class RacingChassis : Chassis { override func description() -> String { return "Racing Chassis" } func racingChassisMethod() -> String { return "Wrooom" } } class Car { let chassis = Chassis() } class RaceCar: Car { override var chassis: RacingChassis { get { return self.chassis } set { self.chassis = newValue } } } var car = Car() car.chassis.description() var raceCar = RaceCar() raceCar.chassis.description() raceCar.chassis.racingChassisMethod() 

Tente isto:

 class Chassis{ var chassis{ return "chassis" } } class RacingChassis:Chassis{ var racing{ return "racing" } } class Car { let chassis: Type init(chassis:Type){ self.chassis = chassis } } class RaceCar: Car { var description{ return self.chassis.racing } } 

Então:

 let racingChassis = RacingChassis() let raceCar = RaceCar(chassis:racingChassis) print(raceCar.description) //output:racing 

Detalhe em http://www.mylonly.com/14957025459875.html

O Solution Dash fornecido funciona bem, exceto que a superclass precisa ser declarada com a palavra-chave let em vez de var. Aqui está uma solução que é possível, mas NÃO RECOMENDADA!

A solução abaixo irá compilar com o Xcode 6.2, SWIFT 1.1 (se todas as classs estiverem em arquivos swift diferentes), mas deve ser evitado, pois pode levar a comportamentos inesperados (incluindo uma falha, especialmente ao usar tipos não-opcionais). NOTA: ISTO NÃO FUNCIONA COM O XCODE 6.3 BETA 3, SWIFT 1.2

 class Chassis {} class RacingChassis : Chassis {} class Car { var chassis:Chassis? = Chassis() } class RaceCar: Car { override var chassis: RacingChassis? { get { return super.chassis as? RacingChassis } set { super.chassis = newValue } } } 

Teoricamente, você pode fazer assim …

 class ViewController { var view: UIView! { return _view } private var _view: UIView! } class ScrollView : UIView {} class ScrollViewController : ViewController { override var view: ScrollView! { return super.view as ScrollView! } } class HomeView : ScrollView {} class HomeViewController : ScrollViewController { override var view: HomeView! { return super.view as HomeView! } } 

Isso funciona perfeitamente em um playground Xcode.

Mas , se você tentar isso em um projeto real, um erro do compilador informará:

A declaração ‘view’ não pode sobrepor mais de uma declaração da superclass

Eu só verifiquei o Xcode 6.0 GM a partir de agora.

Infelizmente, você terá que esperar até que a Apple conserte isso.

Eu também enviei um relatório de bug. 18518795

Eu vi muitas razões porque projetar uma API usando variables ​​em vez de funções é problemático e para mim usar propriedades calculadas parece uma solução alternativa. Há boas razões para manter suas variables ​​de instância encapsuladas. Aqui eu criei um protocolo Automobile que o carro está de acordo. Esse protocolo possui um método de access que retorna um object Chassis. Como o carro está em conformidade com ele, a subclass RaceCar pode substituí-lo e retornar uma subclass diferente do chassi. Isso permite que a class Car programe para uma interface (Automobile) e a class RaceCar que conhece o RacingChassis pode acessar a variável _racingChassis diretamente.

 class Chassis {} class RacingChassis: Chassis {} protocol Automobile { func chassis() -> Chassis } class Car: Automobile { private var _chassis: Chassis init () { _chassis = Chassis() } func chassis() -> Chassis { return _chassis } } class RaceCar: Car { private var _racingChassis: RacingChassis override init () { _racingChassis = RacingChassis() super.init() } override func chassis() -> Chassis { return _racingChassis } } 

Outro exemplo de por que criar uma API usando variables ​​é decomposto quando você tem variables ​​em um protocolo. Se você quiser dividir todas as funções de protocolo em extensões, você pode, exceto que as propriedades armazenadas não podem ser colocadas em extensões e precisam ser definidas na class (para obter isso, compile você teria que descomentar o código em Classe AdaptableViewController e remova a variável de modo da extensão):

 protocol Adaptable { var mode: Int { get set } func adapt() } class AdaptableViewController: UIViewController { // var mode = 0 } extension AdaptableViewController: Adaptable { var mode = 0 // compiler error func adapt() { //TODO: add adapt code } } 

O código acima terá este erro de compilador: “Extensões podem não ter propriedades armazenadas”. Veja como você pode rewrite o exemplo acima para que tudo no protocolo possa ser separado na extensão usando funções:

 protocol Adaptable { func mode() -> Int func adapt() } class AdaptableViewController: UIViewController { } extension AdaptableViewController: Adaptable { func mode() -> Int { return 0 } func adapt() { // adapt code } } 

Tente isto:

 class Chassis {} class RacingChassis : Chassis {} class SuperChassis : RacingChassis {} class Car { private var chassis: Chassis? = nil func getChassis() -> Chassis? { return chassis } func setChassis(chassis: Chassis) { self.chassis = chassis } } class RaceCar: Car { private var chassis: RacingChassis { get { return getChassis() as! RacingChassis } set { setChassis(chassis: newValue) } } override init() { super.init() chassis = RacingChassis() } } class SuperCar: RaceCar { private var chassis: SuperChassis { get { return getChassis() as! SuperChassis } set { setChassis(chassis: newValue) } } override init() { super.init() chassis = SuperChassis() } } 

Basta definir uma nova propriedade imageview com uma convenção de nomenclatura diferente, como imgview, porque imageView já é sua propriedade e não podemos atribuir duas propriedades fortes.

Você pode consegui-lo com o uso de genéricos:

 class Descriptor { let var1 = "a" } class OtherDescriptor: Descriptor { let var2 = "b" } class Asset { let descriptor: D init(withDescriptor descriptor: D) { self.descriptor = descriptor } func printInfo() { print(descriptor.var1) } } class OtherAsset: Asset { override func printInfo() { print(descriptor.var1, descriptor.var2) } } let asset = Asset(withDescriptor: Descriptor()) asset.printInfo() // a let otherAsset = OtherAsset(withDescriptor: OtherDescriptor()) otherAsset.printInfo() // ab 

Com esta abordagem, você terá 100% de código seguro sem forçar a abertura.

Mas isso é uma espécie de hack, e se você precisar redefinir várias propriedades, as declarações de class parecerão uma bagunça total. Portanto, tenha cuidado com essa abordagem.

 class Chassis {} class RacingChassis : Chassis {} class Car { fileprivate let theChassis: Chassis var chassis: Chassis { get { return theChassis } } fileprivate init(_ chassis: Chassis) { theChassis = chassis } convenience init() { self.init(Chassis()) } } class RaceCar: Car { override var chassis: RacingChassis { get { return theChassis as! RacingChassis } } init() { super.init(RacingChassis()) } } 

Você pode simplesmente criar outra variável do RacingChassis.

 class Chassis {} class RacingChassis : Chassis {} class Car { let chassis: Chassis init(){ chassis = Chassis() }} class RaceCar: Car { let raceChassis: RacingChassis init(){ raceChassis = RacingChassis() }}