简体   繁体   中英

How do I use #keyPath() in Swift 4?

I think part of my problem is because Swift 4 has changed the way things like @objc work.

There are a lot of tutorials floating around, with a lot of different values, and I can't pick my way between what used to work in what version enough to figure out how to make it work in this version.

let delegate = UIApplication.shared.delegate as! AppDelegate
delegate.addObserver(self, forKeyPath: #keyPath(AppDelegate.session), options: [], context: nil)
// Warning: Argument of #keyPath refers to non-'@objc' property 'session'

Adding @objc to the var declaration just informs me that APISession can't be referenced in Objective-C. That seems to lead down the path towards requiring me to expose every class / variable I want to use this tool with to Obj-C, and that just seems backwards -- this is a newer feature, as I understand it, and it's just odd that Apple wouldn't make it work natively in Swift. Which, to me, suggests I'm misunderstanding or misapplying something, somewhere, somehow.

According to the docs :

In Objective-C, a key is a string that identifies a specific property of an object. A key path is a string of dot-separated keys that specifies a sequence of object properties to traverse.

Significantly, the discussion of #keyPath is found in a section titled "Interacting with Objective-C APIs". KVO and KVC are Objective-C features.

All the examples in the docs show Swift classes which inherit from NSObject.

Finally, when you type #keyPath in Xcode, the autocomplete tells you it is expecting an @objc property sequence .

在此输入图像描述

Expressions entered using #keyPath will be checked by the compiler (good!), but this doesn't remove the dependency on Objective-C.

This is how I've applied #keyPath() in real project of mine. I used it to save & retrieve data to and from UserDefaults and I called that feature as AppSettings . Here's how things are going on...

1) . I have a protocol called AppSettingsConfigurable It contains a couple of stuffs which are the setting features of my app 🙂...

//: AppSetting Protocol
@objc protocol AppSettingsConfigurable {
    static var rememberMeEnabled : Bool { get set }
    static var notificationEnabled : Bool { get set }
    static var biometricEnabled : Bool { get set }
    static var uiColor: UIColor? { get set }
}

2) . I have class and I named it AppSettings 😉. This is where saving and retrieving operation take place with UserDefaults

//: AppSettings
class AppSettings: NSObject {
    fileprivate static func updateDefaults(for key: String, value: Any) {
        // Save value into UserDefaults
        UserDefaults.standard.set(value, forKey: key)
    }

    fileprivate static func value<T>(for key:String) -> T? {
        // Get value from UserDefaults
        return UserDefaults.standard.value(forKey: key) as? T
    }
}

3) . Here's where BIG things are happened 😍. Conform AppSettings class to our protocol and lets implement the stuffs using #keyPath() .

//: Conform to protocol
extension AppSettings:AppSettingsConfigurable{
    /** get & return remember me state */
    static var rememberMeEnabled: Bool {
        get { return AppSettings.value(for: #keyPath(rememberMeEnabled)) ?? false }
        set { AppSettings.updateDefaults(for: #keyPath(rememberMeEnabled), value: newValue) }
    }

    /** get & return notification state */
    static var notificationEnabled: Bool {
        get { return AppSettings.value(for: #keyPath(notificationEnabled)) ?? true }
        set { AppSettings.updateDefaults(for: #keyPath(notificationEnabled), value: newValue) }
    }

    /** get & return biometric state */
    static var biometricEnabled: Bool {
        get { return AppSettings.value(for: #keyPath(biometricEnabled)) ?? false}
        set { AppSettings.updateDefaults(for: #keyPath(biometricEnabled), value: newValue) }
    }

    /** get & return biometric state */
    static var uiColor: UIColor? {
        get { return AppSettings.value(for: #keyPath(uiColor)) }
        set { AppSettings.updateDefaults(for: #keyPath(uiColor), value: newValue!) }
    }
}

PS : Noticed something different with uiColor from the rest? Nothing wrong with it as it's optional and it's allowed to accept the nil 😍

BOOM🔥..Done! Lets use it..

Usage :

//: Saving...
AppSettings.biometricEnabled = true 

//: Retrieving...
let biometricState = AppSettings.biometricEnabled  // true

That's all... 🙄🙄🚀

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM