【问题标题】:How to override computed property of protocol extension in Swift如何在 Swift 中覆盖协议扩展的计算属性
【发布时间】:2018-09-04 16:31:43
【问题描述】:

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

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 实现中“覆盖”它,但这不起作用。该属性仍然返回零。我该如何解决这个问题?

【问题讨论】:

  • 静态属性不能被覆盖。
  • @usako_lynn 在这种情况下没有静态问题:)

标签: swift protocols swift-extensions computed-properties


【解决方案1】:

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

let currentTheme: Theme.Type = LightTheme.self

currentThemeTheme 的类型,但是您已分配 LightTheme 现在是 Theme 并在您的协议中

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

您已将 nil 作为默认实现返回,该实现正在执行,因为 currentThemeTheme 类型不是 LightTheme,并且它也不是必需的

使用当前的实现解决方案很简单,将currentTheme 声明为LightTheme 请参见下面的答案

let currentTheme: LightTheme.Type = LightTheme.self

保留currentTheme 以简单地分配LightTheme 如下所示

let currentTheme  = LightTheme.self

希望对你有帮助

输出:

轻主题 UIExtendedSRGBColorSpace 1 0 0 1

【讨论】:

  • 这实际上帮助我理解了为什么代码会这样执行。谢谢。
【解决方案2】:

Theme 的扩展没有向协议添加任何要求,它只是向Theme.Type 类型的任何东西添加了一个计算的静态属性。因此,对于 Theme.Type 的任何内容,您都不会覆盖 feature 的默认实现。只有当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 也不需要是可选的并强制解包。

【讨论】:

  • 感谢您的回答。我想避免将功能要求添加到实现主题的文件中。但似乎,没有其他可能。
【解决方案3】:

很抱歉在 cmets 中造成误解。
这里有两个解决方案:
1. 这是@Prashant Tukadiya 的回答。将currentTheme 声明为LightTheme
2. 但是,我认为,出于某种原因,您需要将其设为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 的扩展中定义了一个默认实现,也可以覆盖它。

【讨论】:

    猜你喜欢
    • 2015-10-04
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    • 2018-12-31
    • 1970-01-01
    相关资源
    最近更新 更多