简体   繁体   中英

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. Swift wants to see a default implementation in a protocol extension. I wanted to 'override' it in the actual LightTheme implementation, but that does not work. The property still returns 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

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

With current implementation Solution is simple again is to declare currentTheme as LightTheme See below answer

let currentTheme: LightTheme.Type = LightTheme.self

OR

Keep currentTheme to simply assign LightTheme Like below

let currentTheme  = LightTheme.self

Hope it is helpful to you

Output :

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 . You therefore don't override the default implementation of feature for anything that is a Theme.Type . That would only be the case if feature were an actual requirement of the protocol. 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.

Sorry for misunderstand in comments.
Here are two solutions:
1. It's @Prashant Tukadiya 's answer. Declare currentTheme as LightTheme .
2. I think, however, you need to make it have to be Theme.type for some reason. So declare feature as Theme protocol's property that can(should) be overridden.

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 . Then LightTheme.feature isn't inherited from Theme . And If you did this, Theme.feature can(should) be implemented in subclass. You defined a default implementation in Theme 's extension and can also override it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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