如何正确更新自定义 类 属性?
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)
})
}
}
我有标签、按钮、视图等的自定义 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.
我会为此目的使用键值观察。它有很好的 属性 使用标准化 #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)
})
}
}