プロトコルdynamicKVCKVO関連オブジェクトリソース名管理

5621 ワード

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)
      
            
        } 
    }
    
  • もっと優秀な考え方参考:R.swift SwitGen