KVO has been integral part of Cocoa programming, yet it's not available for pure Swift classes.
Is there a way to implement your own implementation of native KVO?
API Design
When I thought of how I want to implement Observable properties, I’ve had few things in mind:
- Distinct closures for Will/Did set.
- Ability to access current value and old/new one.
- Observable property should work as non-observable one, if function takes int as argument it should work with both cases.
1 and 2 can be satisfied with just API design, sample code for usage of Observable looks like this:
object.property.addObserver(.WillSet) {
println("Will set value to \($0) curValue \($1)”)
}
What I meant by point 3 is best explained with some sample code. Let’s say we have a class Foo in our Library/Module:
struct Foo {
var rawInt = 2
var observableInt = Observable(2)
}
Let’s say user of our library has a function that processes ints:
func processInt(value : Int)
Now I want the users of my module to be able to just use my code, regardless of it beining observable or not:
let object = Foo()
processInt(object.rawInt)
processInt(object.observableInt)
Having a code like this would mean that you as an user of my code doesn’t need to care if it’s observable or not, yet you could leverage that power if you needed/wanted.
Swift Types and Implict conversions
Implementing compliance with above requirement (3rd) wouldn’t be possible in Swift because of Type difference if not for a little known function called __conversion(), conversion as the name clearly states gives you implicit conversion between types, this is how we can use it for our Observable properties:
struct Observable<T> {
var raw : T
// other code...
func __conversion() -> T {
return raw
}
}
Now each time a parameter of T is required, we can use Observable
Swift issues and Wish-list
When I was playing with the idea of Observables I’ve found few things that either crashed the compiler (Ouch) or just didn’t work in language (yet?).
Issues:
- Putting enum declaration in a generic Struct will kill your Xcode -> that’s why ObservingType is separate enum.
- Working with compound collections (Hash of Arrays) has some really weird behaviours:
- don’t try using mapping with observingInfo or compiler crashes -> thus let instead of simple map
- Can’t do inline manipulation of Arrays in hash -> needed to overwrite whole array object in a hash
Wish list:
- Would be nice to have a way to define behaviour/mutability for compound collections
- Ability to create extensions from a generic scope or overload assigment = operator, right now to be able to modify Observable
we need to use rawValue accessor which is far from perfect.
Hopefully Apple is working on at least some of those points.