如何在 Swift 中覆盖协议扩展的计算属性
Posted
技术标签:
【中文标题】如何在 Swift 中覆盖协议扩展的计算属性【英文标题】:How to override computed property of protocol extension in 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 在这种情况下没有静态问题:) 【参考方案1】:你所做的是正确的,但如果你观察你的代码
let currentTheme: Theme.Type = LightTheme.self
currentTheme
是 Theme
的类型,但是您已分配 LightTheme
现在是 Theme
并在您的协议中
extension Theme
static var feature: FeatureTheme.Type!
return nil
您已将 nil
作为默认实现返回,该实现正在执行,因为 currentTheme
是 Theme
类型不是 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
的扩展中定义了一个默认实现,也可以覆盖它。
【讨论】:
以上是关于如何在 Swift 中覆盖协议扩展的计算属性的主要内容,如果未能解决你的问题,请参考以下文章