Weak assignment in Combine
08 Apr 2020 ⇐ Notes archive(This is an entry in my technical notebook. There will likely be typos, mistakes, or wider logical leaps — the intent here is to “let others look over my shoulder while I figure things out.”)
Publisher.assign(to:on:)
comes with a pretty big warning label,
The
Subscribers.Assign
instance created by this operator maintains a strong reference toobject
[…]
and we need to read this label when piping publishers to @Published
properties in ObservableObject
conformances.
Of course, we could do the sink
-weak
-self
-receiveValue
dance. But, that’s a bit of ceremony.
My first instinct was to weak
-ly overload assign
and PR’d it to CombineExt
, in case it’d help others, too. And with some distance and thoughtful feedback from both Shai and Adam, I decided to re-think that instinct.
There’s a few downsides to Publisher.weaklyAssign(to:on)
.
- It crowds an already packed
Publisher
namespace. - In its current form, it doesn’t relay which argument is
weak
ly captured. A clearer signature would be.assign(to:onWeak:)
(and similarly, for anunowned
variant).
Adam mentioned a couple of alternatives:
-
“Promote” the
weak
keyword to a sort of function by way of aWeakBox
type and assign onto it. I tried to make this work—learning more than I bargained for about dynamic member lookup along the way—and ran into a tradeoff dead end. -
Encode the weak capture semantics at the type level à la the
Bindings
package. Which, felt a bit out of scope forCombineExt
, since it’s more of an operator collection.
So, I’m back to where I started and with a slightly modified overload. Gist’ing it below for the curious.
Now call sites can read—
Ah! Almost forgot. Writing tests for the operator had me reaching for Swift.isKnownUniquelyReferenced(_:)
—“a [free-function] I haven’t heard [from] in a long time, a long time.”