6

I have the following code to create an observable property for data binding. It's in the works so I'm not sure what the final implementation is going to be and I'm still pretty new to Swift.

class Observable<T> {
    typealias Observer = T -> Void

    var value: T {
        didSet {
            for observer in self.observers {
                observer?(self.value)
            }
        }
    }

    var observers: [Observer?] = []

    init(_ val: T) {
        self.value = val
    }
}

I would like to keep weak references to the Observer closures. I don't want to rely on the client to ensure that the closure is weak/unowned before passing it in, via the capture list. Especially because there can be many observable properties on a given class.

Is it possible to make the closure references weak in my Observable class?

UPDATE:

I found a couple of resources that I think will help me accomplish what I want:

Make self weak in methods in Swift

specifically,

func methodPointer<T: AnyObject>(obj: T, method: (T) -> () -> Void) -> (() -> Void) {
  return { [unowned obj] in method(obj)() }
}

The following link refers to the above stackoverflow answer and goes into some more detail:

http://blog.xebia.com/2014/10/09/function-references-in-swift-and-retain-cycles/

and this is a two-way binding example:

http://five.agency/solving-the-binding-problem-with-swift/

specifically,

class BondBox<T> {
  weak var bond: Bond<T>?
  init(_ b: Bond<T>) { bond = b }
}

where the listener is wrapped in a class called Bond, which is weakly referenced in the BondBox.

Community
  • 1
  • 1
lintmouse
  • 5,079
  • 8
  • 38
  • 54

2 Answers2

7

Is it possible to make the closure references weak in my Observable class

No. Only class instances can be referred to via weak references in Swift, and a function is not a class instance. (And not only must they be class instances, they must be an Optional wrapping a class instance.)

There are some pretty obvious ways around this, or course - the simplest being a wrapper class. But I do not actually recommend that in this situation, because you have not convinced me that weak references to functions are needed here in the first place. Remember, a weak reference to an object to which there is no strong reference will instantly lose the reference and will be pointing at nil. I can't believe that is what you want. I think you're barking up a wrong tree here.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Ultimately I want the observer's lifetime to be independent of the observable classes lifetime. Is that not an issue here? – lintmouse Jun 04 '15 at 03:26
  • Of course it's an issue. But it has nothing to do with the reference to the _function_ being weak. It has to do with the reference to the observed instance inside the function being weak. It is up to the caller to say `weak self`, just as you said; there is no magic way around it (certainly making the reference to the function weak is not a magic way around it). – matt Jun 04 '15 at 05:16
  • Or you could very sensibly make `self.value` weak. So then if it happens to be nil you just wouldn't call the observers. Pretty simple actually. But maybe that wouldn't solve the problem, sorry. – matt Jun 04 '15 at 05:18
-2

Weak/strong are for memory management of objects, so only apply for variables of reference types (i.e. types which point to objects). Function types in Swift are not reference types, and therefore it does not make sense to talk about weak/strong for their variables.

Plus, you do not actually have variables of function type in your code (except in the middle of the iteration). You simply have a variable of array type. Even in Objective-C, you can only mark variables as weak or strong, not values that are stored inside other things.

And if you were to write the thing you are writing in Objective-C, you would want the "Observable" to have strong references to the closures. Otherwise, who else would have a strong reference to the closure?

newacct
  • 119,665
  • 29
  • 163
  • 224
  • So can an Observable object keep another object alive purely by containing a closure that the other object passed in? To me it would seem that the references captured in the closure would make that possible. If so, then that is the problem I'm trying to solve. In .NET there is the weak event pattern, and is commonly applied to data-binding. Trying to figure out if that is an issue in Swift as well. – lintmouse Jun 07 '15 at 16:36
  • @dustmouse: Why don't you first think about how to do this in Objective-C. If you were to do this in Objective-C, it would keep strong references to the closures, and the provider of the closure decides whether the closure has weak or strong references to other things. It shouldn't be up to the Observable to decide these things; it should be up to the user of the Observable to design the closure to fit its needs. – newacct Jun 07 '15 at 20:40
  • Well ideally not every single listener would have to implement the weak observer pattern and it could be managed in a central place like WeakEventManager in. NET. But I'm probably not thinking about this problem the swift/obj-c way and that's what I'm hung up on. – lintmouse Jun 07 '15 at 21:05