如何在 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

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 的扩展中定义了一个默认实现,也可以覆盖它。

【讨论】:

以上是关于如何在 Swift 中覆盖协议扩展的计算属性的主要内容,如果未能解决你的问题,请参考以下文章

Swift 扩展(Extension)总结

Swift学习:扩展(Extensions)

Swift协议扩展覆盖

6.Swift协议|扩展|访问权限|异常调试|类型转换|运算函数|ARC|类类型初试化器|值类型初始化器

Swift getter 覆盖非计算变量

《从零开始学Swift》学习笔记(Day 50)——扩展计算属性方法