Protocols are a great tool to define some type of configuration because it gives flexibility. SwiftUI, for example, uses to define styles for interface elements.
protocol PrimitiveButtonStyle { ... }
protocol PickerStyle { ... }
protocol ListStyle { ... }
The use of protocol here, instead of enumerations, allows the definition of platform-specific styles.
@available(watchOS 6.0, *)
@available(iOS, unavailable)
@available(OSX, unavailable)
@available(tvOS, unavailable)
public struct CarouselListStyle : SwiftUI.ListStyle { ... }
It also allows the implementation of styles in addition to the predefined ones.
struct CustomButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: PrimitiveButtonStyle.Configuration) -> some View {
...
}
}
A downside of this approach is that we lose the use of dot syntax to access the existing styles that the use of enumeration would allow. This is particularly problematic in frameworks because it leaves the user completely clueless. This type of styling ends up having a poor usability dependent on documentation, not always as good as it could be, or tips from a text editor, who does not always suggest the right options.
Picker(selection: $selectedOption, label: Text("Option")) {
...
}
.pickerStyle(???)
One may try declare a static property in the protocol only to realize that this is not currently possible.
extension PickerStyle {
static var wheels = WheelPickerStyle() // Swift Compiler Error: Static stored properties not supported in protocol extensions
}
I propose to introduce a concrete keyword that would allow the declaration of a static like property in a protocol extension but constrained to a concrete implementation of it, hence a new keyword instead of use static.
extension PickerStyle {
concrete var wheels = WheelPickerStyle()
}
This would give us the flexibility of protocols and the usability of dot syntax.
Picker(selection: $selectedOption, label: Text("Option")) {
...
}
.pickerStyle(.wheels)