I have an object that lives in my app (say a User object) that I want to be published (because some UI depends on it). I don't want to pass it as an EnvironmentObject because of the Liskov substitution principle so I decided to make a wrapper. Something like this:
protocol HasUser: ObservableObject {
var user: String { get }
}
class HasUserWrapper: HasUser {
var user: String { userGetter() }
private let userGetter: () -> String
let objectWillChange: AnyPublisher<Void, Never>
init<UO: HasUser>(wrapping userObject: UO) {
self.objectWillChange = userObject
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.userGetter = { userObject.user }
}
}
extension HasUser {
func eraseToHasUserWrapper() -> HasUserWrapper {
HasUserWrapper(wrapping: self)
}
}
class ConcreteHasUser: HasUser {
@Published var user: String = "john"
}
struct UserView {
@ObservedObject var hasUser: HasUserWrapper = ConcreteHasUser().eraseToHasUserWrapper()
var body: some View {
Text(hasUser.user)
}
}
Now, I would like to make this wrapper generic. So I started something like this:
protocol HasThing: ObservableObject {
associatedtype Thing
var thing: Thing { get }
}
class HasThingWrapper<Thing>: HasThing {
var thing: Thing { thingGetter() }
private let thingGetter: () -> Foo
let objectWillChange: AnyPublisher<Void, Never>
init<HasThingType: HasThing>(wrapping hasThing: HasThingType) {
self.objectWillChange = hasThing
.objectWillChange
.map { _ in () }
.eraseToAnyPublisher()
self.thingGetter = { hasThing. }
}
}
extension HasThing {
func eraseToThingWrapper() -> HasThingWrapper<Thing> {
HasThingWrapper(wrapping: self)
}
}
protocol HasString: HasThing {
var thing: String { get }
}
class StringHolder: HasString {
@Published var thing: String = "hello"
}
How do I tell the compiler that the generic type Thing inside the wrapper should match the associatedtype Thing in the HasThing protocol?
CodePudding user response:
If I understand correctly, you just need to add a generic constraint in the init
:
init<HasThingType: HasThing>(wrapping hasThing: HasThingType)
where HasThingType.Thing == Thing
{
...
// then you can do:
self.thingGetter = { hasThing.thing }
}