Search code examples
swiftfoundation

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?


Solution

  • 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)