Reputation: 877
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?
Upvotes: 4
Views: 2952
Reputation: 543
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.
Upvotes: 1
Reputation: 16446
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
Upvotes: 1
Reputation: 152
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.
Upvotes: 1