Earl Grey Earl Grey - 4 months ago 15
Swift Question

How to embed a static struct in a Swift class?

I need to observe a Unicorn class (inherits from NSObject), but for business reasons, I cannot use a proper reactive framework to have observable properties.
I have to fallback to KVO (god help me).

To make things NOT "stringly-typed", I have an idea of introducing a static property called observableKeyPaths which would provide all the keyPaths that are actually KVO-observable for the Unicorn class...using dot notation.

Let's have an example. The Unicorn class has a property

status
that can be KVOed.
Then when I would be setting up my observer, I would want to reference the keypath like this:

unicornInstance.addObserver(self, forKeyPath: Unicorn.observableKeyPaths.status ...etc..)


I can come up with a struct like this:

struct UnicornObservableKeyPaths {

static let status = "status"
}


This struct can be referenced easily:

UnicornObservableKeyPaths.status


But how do I make this struct part of the class?
The following is not working for me:

class Unicorn {

dynamic private(set) var status: String

static let observableKeyPaths: UnicornObservableKeyPaths = UnicornObservableKeyPaths()

}


Any ideas? What am I missing here?
When I reference the static property..I can access this

Unicorn.observableKeyPaths


but not the
status
static member of the struct..why?

Answer

You can't reference the static property because UnicornObservableKeyPaths() is an actual UnicornObservableKeyPaths and status is a static variable.

You can reference the struct itself using

static let observableKeyPaths = UnicornObservableKeyPaths.self
let _ = Unicorn.observableKeyPaths.status

You can just nest the struct inside of your class

class Unicorn : NSObject {
    dynamic private(set) var status: String = ""

    struct ObservableKeyPaths {

        static let status = "status"
    }
}

Your observing example would look like this:

let unicornInstance = Unicorn()
unicornInstance.addObserver(self, forKeyPath: Unicorn.ObservableKeyPaths.status, options: [], context: nil)