如何使用类扩展覆盖协议扩展?

时间:2018-06-27 00:31:43

标签: swift swift-protocols swift-extensions swift-class

假设我有一个颜色模型:

protocol Color {
    var value: String? { get }
}

class UnknownColor: Color {
    let value: String? = nil
}

class KnownColor: Color {
    let value: String?

    init(value: String? = nil) {
        self.value = value
    }
}

在视图文件中,我向我的颜色模型添加了一些视图细节。 这些细节不是特定于模型的,而是特定于视图的。

fileprivate extension Color {
    fileprivate var representation: String {
        return self.value!
    }
}

fileprivate extension UnknownColor {
    fileprivate var representation: String {
        return "#000"
    }
}

现在,当我在视图文件中使用颜色模型时,我希望我的UnknownColor可以将自己表示为"#000",但是UnknownColor强制转换为Color

let color1 = KnownColor()
let color2 = KnownColor(value:"#fff")
let color3 = UnknownColor()

color1.representation  // Fatal error  (GOOD)
color2.representation  // "#fff"  (GOOD)
color3.representation  // "#000" (GOOD)

if let color = color3 as? Color {
    color.representation // Fatal error  (BAD, expected "#000")
}

我想避免对UnknownColor进行公然的类型检查,因此这样的解决方案并不理想:

func colorRepresentation(_ color: Color) {
    if let color = color as? UnknownColor {
        return "#000"
    } else {
        return color.value!
    }
}

我想不惜一切代价避免对Color模型进行进一步的更改。

可能Color协议的许多实现都想利用Color.representation,因此将extension Color更改为extension KnownColor并不是一种选择。

有没有一种方法可以重组我的代码,以便在UnknownColor.representation实际上是Color时使用UnknownColor

1 个答案:

答案 0 :(得分:2)

我将您的代码直接复制并粘贴到一个Playground中,它运行良好(color3.representation ==“#000”)。

扩展名是否在单独的文件中?如果是这样,fileprivate关键字将使它们对类不可见。

作为参考,这是我放入Playground的全部代码:

protocol Color {
    var value: String? { get }
}

class UnknownColor: Color {
    let value: String? = nil
}

class KnownColor: Color {
    let value: String?

    init(value: String? = nil) {
        self.value = value
    }
}

fileprivate extension Color {
    fileprivate var representation: String {
        return self.value!
    }
}

fileprivate extension UnknownColor {
    fileprivate var representation: String {
        return "#000"
    }
}

let color1 = KnownColor()
let color2 = KnownColor(value:"#fff")
let color3 = UnknownColor()

//color1.representation  // Fatal error  (GOOD)
color2.representation  // "#fff"  (GOOD)
color3.representation  // Fatal error  (BAD, expected "#000")