简体   繁体   English

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

[英]How to override computed property of protocol extension in Swift

I want to implement a theming in a way, that a feature can add its needed colors to a Theme protocol, so that any actual theme implementation must provide colors for every feature. 我想以某种方式实现主题化,即功能可以将其所需的颜色添加到主题协议中,以便任何实际的主题实现都必须为每个功能提供颜色。 I also want to have the theme implementation and feature theme requirements in separate files. 我还希望在单独的文件中具有主题实现和功能主题要求。 I don't want to remove lines of code manually, if I move either theming or feature into another project. 如果将主题或功能部件移动到另一个项目中,我不想手动删除代码行。

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

So, I wanted to add the FeatureTheme requirement to the Theme protocol via extension. 因此,我想通过扩展将FeatureTheme需求添加到主题协议中。 Swift wants to see a default implementation in a protocol extension. Swift希望在协议扩展中看到默认的实现。 I wanted to 'override' it in the actual LightTheme implementation, but that does not work. 我想在实际的LightTheme实现中“覆盖”它,但这不起作用。 The property still returns nil. 该属性仍然返回nil。 How can I solve this? 我该如何解决?

You have done is correct but if you observe your code 您所做的是正确的,但是如果您遵守自己的代码

let currentTheme: Theme.Type = LightTheme.self

currentTheme is type of Theme however you have assigned LightTheme which is now Theme and in your protocol currentThemeTheme类型,但是您已将LightTheme分配为Theme并且已在您的协议中

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

You have nil returned as default implementation which is executing because currentTheme is Theme Type not LightTheme and it is not required properly as well 您已返回nil作为正在执行的默认实现,因为currentThemeTheme类型而不是LightTheme ,并且也没有正确要求

With current implementation Solution is simple again is to declare currentTheme as LightTheme See below answer 使用当前实现,解决方案很简单,就是将currentTheme声明为LightTheme参见以下答案

let currentTheme: LightTheme.Type = LightTheme.self

OR 要么

Keep currentTheme to simply assign LightTheme Like below 保持currentTheme即可像下面那样简单分配LightTheme

let currentTheme  = LightTheme.self

Hope it is helpful to you 希望对您有帮助

Output : 输出:

LightTheme UIExtendedSRGBColorSpace 1 0 0 1 LightTheme UIExtendedSRGBColorSpace 1 0 0 1

The extension of Theme does not add any requirements to the protocol, it just adds a computed static property to anything of type Theme.Type . Theme的扩展不会对协议添加任何要求,它只是将计算出的静态属性添加到Theme.Type类型的任何内容中。 You therefore don't override the default implementation of feature for anything that is a Theme.Type . 因此,对于任何Theme.Type ,您都不会覆盖feature的默认实现。 That would only be the case if feature were an actual requirement of the protocol. 只有feature是协议的实际要求时,情况才会如此。 Maybe something like this: 也许是这样的:

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"

Then there would also be no need for feature to be optional and force unwrapped. 然后,也就不需要feature是可选的并强制展开。

Sorry for misunderstand in comments. 很抱歉在评论中有误解。
Here are two solutions: 这是两个解决方案:
1. It's @Prashant Tukadiya 's answer. 1.这是@Prashant Tukadiya的答案。 Declare currentTheme as LightTheme . currentTheme声明为LightTheme
2. I think, however, you need to make it have to be Theme.type for some reason. 2.但是,我认为由于某种原因,您必须将其设置为Theme.type So declare feature as Theme protocol's property that can(should) be overridden. 因此,将feature声明为Theme协议的属性,可以(应该)将其重写。

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

If you didn't do this, the definition of Theme.feature is just a static property of Theme . 如果您不这样做,则Theme.feature的定义只是Theme的静态属性。 Then LightTheme.feature isn't inherited from Theme . 然后LightTheme.feature不会从Theme继承。 And If you did this, Theme.feature can(should) be implemented in subclass. 如果这样做, Theme.feature可以(应该)在子类中实现Theme.feature You defined a default implementation in Theme 's extension and can also override it. 您在Theme的扩展中定义了默认实现,也可以覆盖它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM