4

I see potential for use of willSet & didSet to replace parts of KVO-type code I'd use in Objective-C. One of the benefits of Objective-C is it's dynamism, specially the ability to create behavior at runtime. In order for willSet & didSet to be useful for me, I need to be able to dynamically assign their behavior. Is it possible to set their "contents" or the behavior they embody dynamically? One use case would be to bind properties of a model to a view. In pseudo-code:

mvvm = new MVVM(packageModel, 'url', packageView, 'urlLabel')
class MVVM {
  init(model: Model, modelPropertyName : NSString, view: View, viewPropertyName : NSString) {
    model.propertyDescriptor('willSet', modelPropertyName, (newUrl){
      view[viewPropertyName].text = newUrl
    })
  }
}
Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
james_womack
  • 10,028
  • 6
  • 55
  • 74
  • It seems you are looking for a replacement for KVO. Swift doesn't have KVO and I'm not sure if there has been official word from Apple about how this kind of architecture will change. But you would be perfectly able to, for example, keep a list of listeners to property changes (which would basically be an array of functions). – jtbandes Aug 03 '14 at 06:12
  • Based on my tests in a playground, Swift does have KVO because NSObject has KVO and Swift has NSObject. I can do it that way but I want to leverage willSet and didSet. – james_womack Aug 03 '14 at 06:54
  • I can halfway get there so far. If I could access the context of willSet dynamically, as in getting the key being set to, I'd be closer. – james_womack Aug 03 '14 at 06:57
  • Could you inject a proxy or filter into/ahead of your model object, so it could watch for changes before forwarding to the model? You'd have to start with a facade backed by data, and inject between so the facade never changes. (poor-man's KVO, I realize) – Chris Conover Sep 19 '14 at 19:44
  • Also, there is a thread posted by Apple on devforums.apple.com soliciting input for future features - you may want to weigh in. – Chris Conover Sep 19 '14 at 19:45
  • I am able to use actual KVO if needed (https://github.com/jameswomack/kvo-in-swift). I might ask for this feature in `didSet` at devforums.apple.com. Thank you @chrisco – james_womack Sep 19 '14 at 20:35

1 Answers1

3

How about something like this:

println("begin")

import Swift


class Observable<T> {
    typealias ChangeNotifier = (T) -> ()

    init(t:T) { self.value = t }

    var value:T { didSet {
        for n in notifiers {
            n(self.value)
        }
    }}

    func subscribe(notifier:ChangeNotifier) {
        notifiers.append(notifier)
    }

    private var notifiers: [ChangeNotifier] = []

}



class ViewModel {
    var numberOfSheep:Observable<Int> = Observable<Int>(t:1)
}

class ViewController {
    var viewModel:ViewModel? = nil { didSet {
        viewModel?.numberOfSheep.subscribe(){ t in
            println("value is now \(t)")
        }}}
}

var vc = ViewController()
var vm = ViewModel()
vc.viewModel = vm

vm.numberOfSheep.value = 2
vm.numberOfSheep.value = 3


println("end")

I tried adding a conversion operator to ModelObserver: "func __conversion() -> T", but it seems that this feature no longer works. I am not sure if there is a work-around. Ideally it could act like a C++ smart pointer, that is to say - transparent.

Chris Conover
  • 8,889
  • 5
  • 52
  • 68
  • I think this is a valuable technique but don't see how it'll allow me dynamically call a subscriber assigned to a specific key/propName without the need to always manually type the keyname in the `didSet` of each observed property. With KVO or setters in a language like JavaScript I have access to context of the key name within the setter. In Swift there's no key name context in `didSet`. I want to be able to do something in `didSet` like `notifiers[currentKey](newValue)` instead of `notifiers['numberOfSheep'](newValue)`. – james_womack Sep 19 '14 at 09:29