如何在Swift中覆盖协议扩展的计算属性

时间:2018-03-26 13:43:48

标签: swift protocols swift-extensions computed-properties

我想以某种方式实现主题,功能可以将其所需的颜色添加到主题协议中,这样任何实际的主题实现都必须为每个功能提供颜色。我还希望将主题实现和功能主题要求放在单独的文件中。如果我将主题或功能移动到另一个项目中,我不想手动删除代码行。

import UIKit

protocol Theme {
    static var genericColor: UIColor { get }
}

protocol FeatureTheme {
    static var featureColor: UIColor { get }
}

extension Theme {
    static var feature: FeatureTheme.Type! {
        return nil
    }
}

struct LightTheme: Theme {
    static var genericColor: UIColor { return .white }

    static var feature: FeatureTheme.Type! { return Feature.self }
    struct Feature: FeatureTheme {
        static var featureColor: UIColor { return UIColor.red }
    }
}

let currentTheme: Theme.Type = LightTheme.self

print(currentTheme) // LightTheme
print(currentTheme.feature.featureColor) // error, because feature is nil

所以,我想通过扩展将FeatureTheme要求添加到Theme协议中。 Swift希望在协议扩展中看到默认实现。我想在实际的LightTheme实现中“覆盖”它,但这不起作用。该物业仍然返回零。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

你做的是正确的,但如果你观察你的代码

let currentTheme: Theme.Type = LightTheme.self

currentTheme的类型为Theme,但您已分配LightTheme,现在为Theme且已在您的协议中

extension Theme {
    static var feature: FeatureTheme.Type! {
        return nil
    }
}

您已将[{1}}作为默认实施方式返回,因为nilcurrentTheme类型不是Theme,并且不需要正确

使用当前实现解决方案再次简单就是将LightTheme声明为currentTheme请参阅下面的答案

LightTheme

OR

保持let currentTheme: LightTheme.Type = LightTheme.self 只需指定currentTheme,如下所示

LightTheme

希望它对你有所帮助

  

输出:

     

LightTheme   UIExtendedSRGBColorSpace 1 0 0 1

答案 1 :(得分:1)

Theme的扩展名不会对协议添加任何要求,只是将计算出的静态属性添加到Theme.Type类型的任何内容中。因此,对于任何feature的内容,您都不能覆盖Theme.Type的默认实现。只有当feature是协议的实际要求时才会出现这种情况。也许是这样的:

protocol Theme {
    static var feature: FeatureTheme.Type { get }
    static var genericColor: UIColor { get }
}

protocol FeatureTheme {
    static var featureColor: UIColor { get }
}

struct LightTheme: Theme {
    static var genericColor: UIColor { return .white }

    static var feature: FeatureTheme.Type { return Feature.self }
    struct Feature: FeatureTheme {
        static var featureColor: UIColor { return UIColor.red }
    }
}

let currentTheme: Theme.Type = LightTheme.self

print(currentTheme) // "LightTheme"
print(currentTheme.feature.featureColor) // "UIExtendedSRGBColorSpace 1 0 0 1"

然后也不需要feature是可选的并且强制解包。

答案 2 :(得分:1)

对于评论中的误解,我们深表歉意 这有两个解决方案:
这是@Prashant Tukadiya的回答。将currentTheme声明为LightTheme 但是,我认为,出于某种原因,你需要使它Theme.type。因此,将feature声明为Theme协议的属性,可以(应该)被覆盖。

protocol Theme {
    static var genericColor: UIColor { get }
    static var feature: FeatureTheme.Type! { get }
}

如果您不这样做,Theme.feature的定义只是Theme的静态属性。然后,LightTheme.feature不会从Theme继承。如果你这样做,Theme.feature可以(应该)在子类中实现。您在Theme的扩展名中定义了默认实现,也可以覆盖它。