This is a very specific and long question, but I'm not smart enough to figure it out by myself..
I was very intrigued by this YouTube-video from raywenderlich.com, which uses the "boxing" method to observe a value.
Their Box
looks like this:
class Box<T> {
typealias Listener = T -> Void
var listener: Listener?
var value: T {
didSet {
listener?(value)
}
init(_ value: T) {
self.value = value
}
func bind(listener: Listener?) {
self.listener = listener
listener?(value)
}
}
It's apparent that only one listener is allowed per "box".
let bindable:Box<String> = Box("Some text")
bindable.bind { (text) in
//This will only be called once (from initial setup)
}
bindable.bind { (text) in
// - because this listener has replaced it. This one will be called when value changes.
}
Whenever a bind like this is set up, the previous binds would be disposed, because Box
replaces the listener
with the new listener.
I need to be able to observe the same value from different places. I have reworked the Box
like this:
class Box<T> {
typealias Listener = (T) -> Void
var listeners:[Listener?] = []
var value:T{
didSet{
listeners.forEach({$0?(value)})
}
}
init(_ value:T){
self.value = value
}
func bind(listener:Listener?){
self.listeners.append(listener)
listener?(value)
}
}
However - this is also giving me trouble, obviously.. There are places where I want the new binding to remove the old binding. For example, if I observe a value in an object from a reusable UITableViewCell
, it will be bound several times when scrolling. I now need a controlled way to dispose specific bindings.
I attempted to solve this by adding this function to Box
:
func freshBind(listener:Listener?){
self.listeners.removeAll()
self.bind(listener)
}
This worked in a way, I could now use freshBind({})
whenever I wanted to remove the old listeners, but this isn't exactly what I want either. I'd have to use this when observing a value from UITableViewCell
s, but I also need to observe the same value from elsewhere. As soon as a cell was reused, I removed the old observers as well as the other observers I needed.
I am now confident that I need a way to retain a disposable object wherever I would later want to dispose them.
I'm not smart enough to solve this on my own, so I need help.
I've barely used some of the reactive-programming frameworks out there (like ReactiveCocoa), and I now understand why their subscriptions return Disposable
objects which I have to retain and dispose of when I need. I need this functionality.
What I want is this: func bind(listener:Listener?)->Disposable{}
My plan was to create a class named Disposable
which contained the (optional) listener, and turn listeners:[Listener?]
into listeners:[Disposable]
, but I ran into problems with <T>
..
Cannot convert value of type 'Box<String?>.Disposable' to expected argument type 'Box<Any>.Disposable'
Any smart suggestions?
Disposable
-object, the first thing I thought was "Oh god, am I creating RxSwift?" :) But I still want to go for this, I (think) I know what I need for this project - which makes me curious, could you elaborate on the issue with this not being thread safe? – Kaye