Recommend ergonomics and design for using protocol based dependencies #2835
-
In a followup to #1021, I wanted to ask for some additional clarification on how to register dependencies that use a protocol interface pattern over the more common TCA pattern of structs and injectable closures. I tend to prefer the former but I find that Swift's type system often gets in the way, particularly when it comes to registering these dependencies via Take the following protocol: public protocol KeyValueStorage: DependencyKey {
associatedtype Key: Hashable
func value<Value>(forKey key: Key) -> Value?
func setValue<Value>(_ value: Value?, forKey key: Key)
subscript<Value>(key: Key) -> Value? { get set }
subscript<Value>(key: Key, default defaultValue: @autoclosure () -> Value) -> Value { get set }
} The first issue is defining the private struct Box {
static let liveValue: some KeyValueStorage = UbiqutiousStorage()
}
extension KeyValueStorage {
static public var liveValue: some KeyValueStorage {
Box.liveValue
}
} Not the prettiest but it works (any suggestions on how to improve this would be great!) The second, and much harder problem to solve is how to then register that protocolized service with extension DependencyValues {
var keyValueStorage: any KeyValueStorage {
get { self[KeyValueStorage.self] }
set { self[KeyValueStorage.self] = newValue }
}
} This doesn't compile unfortunately because of the associated type requirements. It seems there are two options: I can either introduce some kind of type erasure or I can remove the associated type requirements. I was wondering if there are any other suggestions or ways around this problem that people in the TCA community have used. Thanks all! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
After struggling with this for a while, I actually figured out a working solution! I found this section of the dependencies documentation that describes uses a private enum key, which I did. Then when I added conformance to private enum KeyValueStorageKey: DependencyKey {
static var liveValue = UbiqutiousStorage() as any KeyValueStorage
}
extension DependencyValues {
public var keyValueStorage: any KeyValueStorage {
get { self[KeyValueStorageKey.self] }
set { self[KeyValueStorageKey.self] = newValue }
}
} I just had to type-cast the underlying concrete implementation to |
Beta Was this translation helpful? Give feedback.
After struggling with this for a while, I actually figured out a working solution! I found this section of the dependencies documentation that describes uses a private enum key, which I did. Then when I added conformance to
DependencyKey
:I just had to type-cast the underlying concrete implementation to
any KeyValueStorage
and it worked!