美文网首页
协议 dynamic KVC\KVO 关联对象 资源名管理

协议 dynamic KVC\KVO 关联对象 资源名管理

作者: 曹来东 | 来源:发表于2019-08-07 17:56 被阅读0次

    只能被class继承的协议

    • @objc修饰的协议,还可以暴露给OC去遵守实现
            protocol Runnable : AnyObject {}
            protocol Runnable : class {}
            @objc protocol Runnable: {}
    

    可选协议

    • 可以通过@objc定义可选协议,这种协议只能被class遵守
    @objc protocol Runnable {
        func run1()
        @objc optional func run2()//可选协议
        func run3()
    }
    
    class HomeViewController: UIViewController, Runnable {
        func run1() {
            
        }
        
        func run3() {
            
        }
    }
    

    dynamic

    • @objc dynamic修饰的内容会具有动态性,比如调用方法会走runtime那一套流程
    class Dog: NSObject {
        @objc dynamic func test1(){}//runTime流程
        func test2() { }//虚表
    }
    

    KVC \ KVO

    • Swift支持KVC\KVO的条件
    • 属性所在的类,监听器最终继承自NSObject
    • @objc dynamic修饰对应的属性
    class Observer: NSObject {
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            
            print("observeValue",change?[.oldKey] ?? (Any).self)
            print("observeValue",change?[.newKey] ?? (Any).self)
        }
    }
    
    class Person: NSObject {
        @objc dynamic var age: String = "0"
        var observer: Observer = Observer()
        override init() {
            super.init()
            self.addObserver(observer, forKeyPath: "age", options: [.new,.old], context: nil)
        }
        deinit {
            self.removeObserver(observer, forKeyPath: "age")
        }
    }
    
    class HomeViewController: UIViewController {
    
        
        override func viewDidLoad() {
            
            let p = Person()
            p.age = "20"
            p.age = "30"
            p.setValue("25", forKey: "age")
       
        } 
    }
    //打印结果
    observeValue 0
    observeValue 20
    observeValue 20
    observeValue 30
    observeValue 30
    observeValue 25
    

    block方式的KVO

    class Person: NSObject {
        @objc dynamic var age: Int = 0
        var observation: NSKeyValueObservation?
        override init() {
            super.init()
            observation = observe(\Person.age, options: .new, changeHandler: { (_, change) in
                print(change.newValue as Any)
            })
        }
        
    }
    
    class HomeViewController: UIViewController {
    
        override func viewDidLoad() {
            
            let p = Person()
            p.age = 10
       
        } 
    }
    

    关联对象(Associated Object)

    • Swift中,class依然可以使用关联对象
    • 默认情况extension不可以增加存储属性
    • 借助关联对象,可以实现类似extensionclass增加存储属性的效果
    class Person { }
    extension Person {
        private static var AGE_KEY: Void?
        var age: Int {//可读 可写计算属性,不占用内存空间
            get {
                (objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
            }
            set {
                objc_setAssociatedObject(self, &Self.AGE_KEY, newValue, .OBJC_ASSOCIATION_ASSIGN)
            }
        }
        
    }
    class HomeViewController: UIViewController {
    
        override func viewDidLoad() {
            
            let p = Person()
            print(p.age)//0
            p.age = 10;
            print(p.age)//10
       
        } 
    }
    

    资源名管理

            let img = UIImage(named: "logo")
            let btn = UIButton(type: .custom)
            btn.setTitle("添加", for: .normal)
            performSegue(withIdentifier: "login_main", sender: self)
    
    • 这种做法实际上参考了Android的资源名管理方式
    enum R {
        enum string: String {
            case add = "添加"
        }
        enum image: String {
            case logo
        }
        enum segue: String {
            case login_main
        }
    }
    
    class HomeViewController: UIViewController {
    
        override func viewDidLoad() {
            
            let img = UIImage(named: R.image.logo.rawValue)
            let btn = UIButton(type: .custom)
            btn.setTitle(R.string.add.rawValue, for: .normal)
            performSegue(withIdentifier: R.segue.login_main.rawValue, sender: self)
       
        } 
    }
    
    enum R {
        enum string: String {
            case add = "添加"
        }
        enum image: String {
            case logo
        }
        enum segue: String {
            case login_main
        }
    }
    
    extension UIImage {
        convenience init?(_ name: R.image) {
            self.init(named: name.rawValue)
        }
    }
    extension UIViewController {
       func performSegue(withIdentifier identifier: R.segue, sender: Any?){
            performSegue(withIdentifier: identifier.rawValue, sender: sender)
        }
    }
    
    extension UIButton {
        func setTitle(_ title: R.string, for state: UIControl.State) {
            setTitle(title.rawValue, for: state)
        }
    }
    class HomeViewController: UIViewController {
    
        override func viewDidLoad() {
            
            let img = UIImage.init(R.image.logo)
            let btn = UIButton(type: .custom)
            btn.setTitle(R.string.add, for: .normal)
            performSegue(withIdentifier: R.segue.login_main, sender: self)
            
        } 
    }
    
    enum R {
        
        enum image {
            static var logo = UIImage(named: "logo")
        }
        enum font {
            static func arial(_ size: CGFloat) -> UIFont? {
                UIFont(name: "Arial", size: size)
            }
        }
    }
    
    
    class HomeViewController: UIViewController {
    
        override func viewDidLoad() {
            
            let img = R.image.logo
            let font = R.font.arial(14)
      
            
        } 
    }
    

    相关文章

      网友评论

          本文标题:协议 dynamic KVC\KVO 关联对象 资源名管理

          本文链接:https://www.haomeiwen.com/subject/fhkadctx.html