Swift iOS:KVO

KVO是Key Value Observer的縮寫,能夠用於監視一個對象的屬性值變化,而後執行一個代碼塊(塊、函數、閉包等)。Facebook開源了一個KVO框架,KVOController。javascript

這個案例使用KVOController,用於App主題改變通知。經過KVO監視主題的值,當設置主題變化時,通知全部的UI類的主題處理器。代碼以下:java

import UIKit
import KVOController
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.window = UIWindow();
        self.window?.frame=UIScreen.main.bounds;
        self.window?.makeKeyAndVisible();
        self.window?.rootViewController = Page()
        return true
    }
}
class Page: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let button   = UIButton(type: .system)
        button.frame = CGRect(x: 120, y: 150, width: 220, height: 50)
        button.contentHorizontalAlignment = .left
        button.setTitle("Peace",for: .normal)
        button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
        view.addSubview(button)
        let button1   = UIButton(type: .system)
        button1.frame = CGRect(x: 120, y: 200, width: 220, height: 50)
        button1.contentHorizontalAlignment = .left
        button1.setTitle("Blood",for: .normal)
        button1.addTarget(self, action: #selector(buttonAction1(_:)), for: .touchUpInside)
        view.addSubview(button1)
        self.themeChangedHandler = {[weak self] (style) -> Void in
            if "Peace" == style{
                self!.view.backgroundColor = .blue
            }
            else{
                self!.view.backgroundColor = .red
            }
        }
    }
    func buttonAction(_ sender:UIButton!){
        ThemeColor.shared.style = "Peace"
    }
    func buttonAction1(_ sender:UIButton!){
        ThemeColor.shared.style = "Blood"
    }
}
class ThemeColor :NSObject  {
    dynamic var style:String
    static let shared = ThemeColor()
    fileprivate override init(){
        style = "Blood"// or Peace
        super.init()
    }
}
extension NSObject {
    fileprivate struct AssociatedKeys {
        static var themeChanged = "themeChanged"
    }
    public typealias ThemeChangedClosure = @convention(block) (_ style:String) -> Void
    var themeChangedHandler:ThemeChangedClosure? {
        get {
            let closureObject: AnyObject? = objc_getAssociatedObject(self, &AssociatedKeys.themeChanged) as AnyObject?
            guard closureObject != nil else{
                return nil
            }
            let closure = unsafeBitCast(closureObject, to: ThemeChangedClosure.self)
            return closure
        }
        set{
            guard let value = newValue else{
                return
            }
            let dealObject: AnyObject = unsafeBitCast(value, to: AnyObject.self)
            objc_setAssociatedObject(self, &AssociatedKeys.themeChanged,dealObject,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            self.kvoController.observe(ThemeColor.shared, keyPath: "style", options: [.initial,.new] , block: {[weak self] (nav, color, change) -> Void in
                self?.themeChangedHandler?(ThemeColor.shared.style)
                }
            )
        }
    }
}複製代碼

代碼運行後,能夠看到兩個按鈕,點擊不一樣的按鈕會切換主題。設計模式

Pod文件爲:閉包

pod 'KVOController', '~> 1.2.0'複製代碼

代碼的效果就是,當修改:app

ThemeColor.shared.style = "Peace"複製代碼

就會引起當前對象的塊對象:themeChangedHandler的調用。由於使用了KVO監視了ThemeColor.shared.style,當值變化的時候,就會引起themeChangedHandler所指向的閉包的執行。閉包在set的時候被使用objc_setAssociatedObject存儲於指定鍵(themeChanged)的值內。當運行get的時候,會使用objc_getAssociatedObject函數把它再取出來。框架

函數對:objc_getAssociatedObject和objc_setAssociatedObject看起來比較複雜,可是能夠用於動態的爲對象建立屬性,所以頗爲強大。ide

此代碼很差理解,也許使用Observer設計模式來替代更好。函數

相關文章
相關標籤/搜索