This is nice: Apple Developer Documentation
…but it can be a pain because WritableKeyPath
is a misnomer. (There still aren't set-only properties. ) What do people do when they want to use the method to set an optional with a non-optional?
This is nice: Apple Developer Documentation
…but it can be a pain because WritableKeyPath
is a misnomer. (There still aren't set-only properties. ) What do people do when they want to use the method to set an optional with a non-optional?
You use map
x
.map { $0 as Optional }
.assign { ... }
Related thread–Combine assign to Optional property: alternate versions?
Thanks.
However, I need to set properties of the Published object, and Publishers.MapKeyPath
doesn't work with that overload, so I think I'm stuck with sink
. And if that's the case, map
isn't necessary, because you can assign a non-optional to an optional, with =
, in the sink
closure.
I don't follow, are you trying to do something like this?
import SwiftUI
import Combine
class Test: ObservableObject {
@Published var a: Int = 3
func test() {
CurrentValueSubject(4)
.map { $0 }
.assign(to: $a)
}
}
Assuming you have Xcode Beta (since the assign
you linked is in beta).
Like that, only where a
has an optional property which needs assigning.
I'm not sure the KeyPath
can work for properties in this case, as the path is to the publisher, not the property. The regular assign
(with the appropriate optional overload) may work.
…but how can we avoid having to store the AnyCancellable
manually? That's what I love about this new assign
overload, but I don't know how it was implemented. Would it have even been possible to implement without private API?
Sorry, I don’t know how the new one is implemented.
Is this maybe what you're looking for? It runs perfectly fine with the new assign(to:)
:
class Test: ObservableObject {
@Published var a: Int? = 3
let subject = CurrentValueSubject<Int, Never>(4)
func test() {
subject
.map({ $0 })
.assign(to: $a)
}
}
let object = Test()
object.$a.sink(receiveValue: { value in
print(value) // Optional(3), Optional(4)
})
object.test()
See my second post — it needs to dig into properties in order to be incredibly useful.
Ah, right. The method isn't designed for that. It's to assign a new value to an @Published
property, not to mutate a property of an @Published
property. (unless that property itself is an @Published
property).
class PublishedObject {
@Published var a: Int? = 3
}
class Test: ObservableObject {
@Published var container = PublishedObject()
let subject = CurrentValueSubject<Int, Never>(4)
func test() {
subject
.map({ $0 })
.assign(to: container.$a)
}
}
let object = Test()
object.container.$a.sink(receiveValue: { value in
print(value) // Optional(3), Optional(4)
})
object.test()
Note that container
doesn't have to be @Published
. The only requirement here is that the target property is @Published
.
The assign(to:)
method connects its subscription lifecycle to that of the target publisher somehow. I don't think you need private APIs for that and it might be possible to build something yourself where you connect the subscription lifecycle to the lifecycle of the target property somehow.