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

How to override computed property of protocol extension in Swift

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

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 实现中 'override' 它,但这不起作用。 属性 仍然是 returns 零。我该如何解决?

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

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

希望对您有所帮助

Output :

LightTheme UIExtendedSRGBColorSpace 1 0 0 1

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是可选的和强制展开的。

对评论中的误会表示抱歉。
这里有两个解决方案:
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 的扩展中定义了默认实现,也可以覆盖它。