如何正确更新自定义 类 属性?

How to update custom classes properties properly?

我有标签、按钮、视图等的自定义 classes

示例class:

class PopupButton: UIButton {
    override func awakeFromNib() {
        self.layer.borderWidth = 1.3
        self.layer.borderColor = fadedTextColor.cgColor
        self.layer.cornerRadius = 10
        self.layer.backgroundColor = whiteColor.cgColor
        self.setTitleColor(textHeaderColor, for: .normal)
    }
}

当我更改颜色时,即:fadedTextColor 我希望此 PopupButton class 立即反映该更改。

我怎样才能做到这一点?

感谢您的宝贵时间。

首先创建一个单例 class 来保存所有 "global" 变量。然后将 didSet 添加到 fadedTextColor 属性 到 post 其值更改时的通知。接下来在您的自定义 class 添加一个观察者和一个选择器,以使用您的单例 class:

中的颜色更改按钮边框颜色
class Shared {
    private init() {}
    static let instance = Shared()
    var fadedTextColor: UIColor = .red {
        didSet {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "fadedTextColorChanged"), object: nil)
        }
    }
    var textHeaderColor: UIColor = .blue
}

class PopupButton: UIButton {
    override func awakeFromNib() {
        super.awakeFromNib()
        layer.borderWidth = 1.3
        layer.borderColor = Shared.instance.fadedTextColor.cgColor
        layer.cornerRadius = 10
        layer.backgroundColor = UIColor.white.cgColor
        setTitleColor(Shared.instance.textHeaderColor, for: .normal)
        NotificationCenter.default.addObserver(self, selector: #selector(colorChanged), name: NSNotification.Name(rawValue: "fadedTextColorChanged"), object: nil)
    }
    @objc func colorChanged(notification: Notification) {
        layer.borderColor = Shared.instance.fadedTextColor.cgColor
    }
}

Swift 3

注意:此答案适用于 Swift 3. 利用 much 更好的 API Swift 4.

我会为此目的使用键值观察。它有很好的 属性 使用标准化 #keyPath 字符串来识别更改,而不是通知的任意字符串。

[.initial, .new] 选项使 observeValue(forKeyPath:of:change:context:) 立即为您调用(设置初始值),并在每次更改后调用(通知新值)。

public final class AppConfig: NSObject {
    static let shared = AppConfig()
    override private init() {}

    @objc dynamic var fadedTextColor: UIColor = .red
    @objc dynamic var textHeaderColor: UIColor = .blue
    // ... add other global config state properties here
    // any pro properties you wish to observe must be `@objc` and ` dynamic`
}

class PopupButton: UIButton {
    override func awakeFromNib() {
        let appconfig = AppConfig.shared

        self.layer.borderWidth = 1.3
        
        appconfig.addObserver(self,
                              forKeyPath: #keyPath(AppConfig.fadedTextColor),
                              options: [.initial, .new], context: nil)
        self.layer.cornerRadius = 10
        self.layer.backgroundColor = UIColor.white.cgColor


        appconfig.addObserver(self,
                              forKeyPath: #keyPath(AppConfig.textHeaderColor),
                              options: [.initial, .new], context: nil)



    }

    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey : Any]?,
        context: UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath, let newValue = change?[.newKey] else { return }

        if object as? AppConfig == AppConfig.shared {
            switch (keyPath, newValue) {
            case (#keyPath(AppConfig.fadedTextColor), let fadedTextColor as UIColor):
                self.layer.borderColor = fadedTextColor.cgColor

            case (#keyPath(AppConfig.textHeaderColor), let textHeaderColor as UIColor):
                self.setTitleColor(textHeaderColor, for: .normal)

            // Handle other changes here

            default: break
            }
        }
    }
}

Swift 4

我们在 Swift 4 中有一个非常好,但文档很少的 API,它使用 KeyPath 进行简洁、类型安全的键值观察。对必须处理所有回调的大量 observeValue(forKeyPath:of:change:context:) 的需求已经一去不复返了。相反,每个观察都有一个闭包,仅当与其相关的事件发生时才调用该闭包。这很好地打破了你的 observeValue(forKeyPath:of:change:context:) 方法。

有关详细信息,请参阅 What's New in Foundation WWDC 2017 视频,大约从 19:30 开始。

public final class AppConfig: NSObject {
    static let shared = AppConfig()
    override private init() {}

    @objc dynamic var fadedTextColor: UIColor = .red
    @objc dynamic var textHeaderColor: UIColor = .blue
    // ... add other global config state properties here
    // any pro properties you wish to observe must be `@objc` and ` dynamic`
}

import UIKit

class PopupButton: UIButton {
    var observers = [NSKeyValueObservation]()

    override func awakeFromNib() {
        let appconfig = AppConfig.shared

        self.layer.borderWidth = 1.3

        observers.append(appconfig.observe(\.fadedTextColor,  options: [.initial, .new]) { object, change in
            self.layer.borderColor = object.fadedTextColor.cgColor
        })
        self.layer.cornerRadius = 10
        self.layer.backgroundColor = UIColor.white.cgColor


        observers.append(appconfig.observe(\.textHeaderColor,  options: [.initial, .new]) { object, change in
            self.setTitleColor(object.textHeaderColor, for: .normal)
        })
    }
}