在Swift中覆盖不同类型的超类属性

时间:2014-06-07 05:50:38

标签: swift

在Swift中,有人可以解释如何使用从原始属性子类化的另一个对象覆盖超类上的属性吗?

举个简单的例子:

class Chassis {}
class RacingChassis : Chassis {}

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

这给出了错误:

Cannot override with a stored property 'chassis'

如果我有底盘作为' var'相反,我得到错误:

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

我唯一可以在指南中找到" Overriding Properties"表示我们必须覆盖getter和setter,这可能有助于更改属性的值(如果它' var'),但是更改属性类呢?

15 个答案:

答案 0 :(得分:102)

Swift不允许您更改任何变量或属性的类类型。相反,您可以在子类中创建一个额外的变量来处理新的类类型:

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")
            }
        }
    }
}

似乎无法使用let语法声明属性并使用var的子类覆盖它,反之亦然,这可能是因为超类实现可能不会期望该属性在初始化后更改。所以在这种情况下,属性需要在超类中用'var'声明,以匹配子类(如上面的代码片段所示)。如果无法更改超类中的源代码,那么每次机箱需要进行变异时,最好摧毁当前的RaceCar并创建一个新的RaceCar。

答案 1 :(得分:9)

这似乎有效

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()

答案 2 :(得分:5)

试试这个:

class Chassis{
     var chassis{
         return "chassis"
     } 
}

class RacingChassis:Chassis{
     var racing{
         return "racing"
     } 
}

class Car<Type:Chassis> {
     let chassis: Type
     init(chassis:Type){
        self.chassis = chassis
     }
}

class RaceCar: Car<RacingChassis> {
     var description{
         return self.chassis.racing
     } 
}

然后:

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

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

中的详细信息

答案 3 :(得分:3)

提供的解决方案Dash运行良好,但必须使用let关键字而不是var声明超类。这是一个可行的解决方案,但不推荐!

下面的解决方案将使用Xcode 6.2,SWIFT 1.1进行编译(如果所有类都在不同的swift文件中),但应该避免,因为它可能导致意外行为(包括崩溃,特别是在使用非可选类型时)。 注意:这不适用于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
        }
    }
}

答案 4 :(得分:1)

理论上,你可以这样做......

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! }
}

这在Xcode游乐场中非常有效。

,如果您在实际项目中尝试此操作,编译器错误会告诉您:

  

声明'view'不能覆盖多个超类声明

我现在只检查过Xcode 6.0 GM。

不幸的是,你必须等到Apple修复此问题。

我也提交了一份错误报告。的 18518795

答案 5 :(得分:1)

我已经看到了很多原因,为什么使用变量而不是函数来设计API是有问题的,对我来说使用计算属性感觉就像一个解决方法。有充分的理由保持实例变量的封装。在这里,我创建了汽车符合的协议汽车。此协议具有一个返回Chassis对象的访问器方法。由于Car符合它,RaceCar子类可以覆盖它并返回不同的Chassis子类。这允许Car类编程到接口(Automobile),知道RacingChassis的RaceCar类可以直接访问_racingChassis变量。

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
    }
}

使用变量分解设计API的另一个例子是在协议中有变量时。如果您想将所有协议功能分解为扩展,则除了存储的属性不能放在扩展中并且必须在类中定义(要进行编译,您必须取消注释中的代码) AdaptableViewController类并从扩展名中删除mode变量:

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
    }
}

以上代码将出现此编译器错误:“扩展可能没有存储属性”。以下是您可以重新编写上述示例的方法,以便通过使用函数将协议中的所有内容分离出来:

protocol Adaptable {
    func mode() -> Int
    func adapt()
}

class AdaptableViewController: UIViewController {
}

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

答案 6 :(得分:0)

您可以简单地创建另一个RacingChassis变量。

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

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

答案 7 :(得分:0)

试试这个:

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()
    }
}

答案 8 :(得分:0)

只需使用不同的命名约定(如imgview)设置新的imageview属性,因为imageView已经是它自己的属性,我们无法分配2个强大的属性。

答案 9 :(得分:0)

您可以使用泛型来实现它:

class Descriptor {
    let var1 = "a"
}

class OtherDescriptor: Descriptor {
    let var2 = "b"
}

class Asset<D: Descriptor> {
    let descriptor: D

    init(withDescriptor descriptor: D) {
        self.descriptor = descriptor
    }

    func printInfo() {
        print(descriptor.var1)
    }
}

class OtherAsset<D: OtherDescriptor>: Asset<D> {
    override func printInfo() {
        print(descriptor.var1, descriptor.var2)
    }
}

let asset = Asset(withDescriptor: Descriptor())
asset.printInfo() // a

let otherAsset = OtherAsset(withDescriptor: OtherDescriptor())
otherAsset.printInfo() // a b

使用这种方法,您将获得100%类型安全的代码,而不需要强制解包。

但是这有点像黑客,如果你需要重新定义几个属性,那么你的类声明看起来就像一团糟。所以要小心这种方法。

答案 10 :(得分:0)

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())
    }
}

答案 11 :(得分:0)

以下内容允许在基类和派生类中使用单个对象。在派生类中,使用派生对象属性。

class Car {
    var chassis:Chassis?

    func inspect() {
        chassis?.checkForRust()
    }
}

class RaceCar: Car {
    var racingChassis: RacingChassis? {
        get {
            return chassis as? RacingChassis
        } 
    }

    override func inspect() {
        super.inspect()
        racingChassis?.tuneSuspension()
    }
}

答案 12 :(得分:0)

根据您计划使用该属性的方式,最简单的方法是为您的子类使用可选类型,并为super覆盖didSet {}方法:

class Chassis { }
class RacingChassis: Chassis { }

class Car {
    // Declare this an optional type, and do your 
    // due diligence to check that it's initialized
    // where applicable
    var chassis: Chassis?
}
class RaceCar: Car {
    // The subclass is naturally an optional too
    var racingChassis: RacingChassis?
    override var chassis: Chassis {
        didSet {
            // using an optional, we try to set the type
            racingChassis = chassis as? RacingChassis
        }
    }
}

显然,您需要花一些时间检查以确保可以通过这种方式初始化类,但是通过将属性设置为optional,可以保护自己免受强制转换不再起作用的情况的影响。

答案 13 :(得分:0)

其他答案略有不同,但是更简单,更安全,并且有一些不错的好处。

class Chassis {}
class RacingChassis : Chassis {}

class Car {
    let chassis = Chassis()
}
class RaceCar: Car {
    var racingChassis: RacingChassis? {
        get {
            return chassis as? RacingChassis
        }
    }
}

好处包括没有限制底盘必须是什么(var,let,optional等),并且很容易将RaceCar子类化。然后,RaceCar的子类可以具有自己的底盘(或RacingChassis)计算值。

答案 14 :(得分:0)

简单使用泛型,例如

class Chassis {
    required init() {}
}
class RacingChassis : Chassis {}

class Car<ChassisType : Chassis> {
    var chassis = ChassisType()
}


let car = Car()
let racingCar = Car<RacingChassis>()
    
let c1 = car.chassis
let c2 = racingCar.chassis
    
print(c1) // Chassis
print(c2) // RacingChassis

此外,Chassis 甚至不需要是子类:

protocol Chassis {
    init()
}
class CarChassis: Chassis{
    required init() {
    }
}
class RacingChassis : Chassis {
    required init() {
    }
}

class Car<ChassisType : Chassis> {
    var chassis = ChassisType()
}