美文网首页
从OC到Swift (二)

从OC到Swift (二)

作者: 冰棍儿好烫嘴 | 来源:发表于2022-01-29 10:29 被阅读0次

    协议

    只能被class继承的协议

    protocol Runnable1: AnyObject{}
    protocol Runnable2: class{}
    @objc protocol Runnable3 {}
    
    • @objc修饰的协议,还可以暴露给OC去遵守实现
    • 可以通过@objc定义可选协议,这种协议只能被class遵守
    @objc protocol Runnable{
        func run1()
        @objc optional func run2()
        func run3()
    }
    
    class Dog: Runnable {
        func run1() { print("Dog run1")}
        func run3() {print("Dog runn3")}
    }
    var d = Dog()
    d.run1()
    d.run3()
    

    dynamic

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

    KVC/KVO

    • Swift支持KVC/KVO的条件
      - 属性所在的类、监听器最终继承自NSObject(KVC/KVO也是依赖于runtime的)
      - 用@objc dynamic 修饰对应的属性

    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: { person, change, in
                print(change.newValues as Any)
            })
        }
    }
    

    关联对象

    • 在Swift中,class依然可以使用关联对象
    • 默认情况,extension不可以增加存储属性,可以增加计算属性,因为计算属性本质是方法,不占用内存
    protocol Runnable {
        
    }
    extension Runnable{
        
    }
    class Person:Runnable {
        var age = 0
    }
    extension Person{
        var weight = 0//报错:Extensions must not contain stored properties
    }
    
      - 借助关联对象,可以实现类似`extension`为`class`增加存储属性的效果
    
    extension Person{
        private static var AGE_KEY : Void?//这里用Void?或者bool类型,目的是为了省内存,Void?或者bool类型都只占用一个字节
        //类型存储属性,本质是全局变量
        var age:Int{
            get{
                objc_getAssociatedObject(self, &Person.AGE_KEY) as! Int
            }
            set {
                objc_setAssociatedObject(self, &Person.AGE_KEY, newValue, .OBJC_ASSOCIATION_ASSIGN)
            }
        }
    }
    var p = Person()
    p.age = 10
    print(p.age)
    

    资源名管理

    • 这种做法实际上是参考了Android的资源名管理方式
    enum R{
        enum string:String {
            case add = "添加"
        }
        enum image:String {
            case logo
        }
        enum segue:String {
            case login_main
        }
    }
    
    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 image {
            static var logo = UIImage(named: "logo")
        }
        enum font {
            static func arial(_ size:CGFloat) -> UIFont?{
                UIFont(name: "Arial", size: size)
            }
        }
    }
    
    let img = R.image.logo
            let font = R.font.arial(14)
    

    多线程开发 - 异步

    //gcd
    DispatchQueue.main.async {
          //拿到主线程
    }
            
    DispatchQueue.global().async {
         //拿到全局并发队列
         print(Thread.current)//打印当前线程
         DispatchQueue.main.async {
              //回到主线程
         }
    }
    

    或者:

    let item = DispatchWorkItem{
        //子线程
        print("1",Thread.current)
    }
    DispatchQueue.global().async(execute: item)
    item.notify(queue: DispatchQueue.main){
        //主线程
        
    }
    

    多线程开发 - 延迟

    let time = DispatchTime.now()+3
            
    DispatchQueue.main.asyncAfter(deadline: time){
         print("1")
    }
    

    多线程开发 - once

    • dispatch_once 在Swift中已被废弃,取而代之
      - 可以用类型属性或者全局变量/常量:静态的存储属性(static),也就是类型存储属性,他在程序运行过程中,只初始化一次,因为本质就是全局变量,全局变量在运动过程中只初始化一次,而且static修饰的属性默认是lazy的,所以只想走一次代码的可以用下面的方法
      - 默认自带 lazy + dispatch_once 效果
    static var age:Int = getAge()
    static func getAge() -> Int{
           print("getAge")
           return 0
    }
    
    print(Self.age)
    print(Self.age)
    print(Self.age)
    //这种办法声明的getAge只会调用一次,即使是所在的ViewController被销毁之后重新创建,age也不会再走一遍初始化getAge的方法
    
    fileprivate var initTask:Void = {
        print("init -------")
    }()
    let _ = initTask
    let _ = initTask
    //只走一次print("init -------")代码
    

    多线程开发 - 加锁

    import Foundation
    
    public struct Cache{
        private static var data = [String:Any]()
        private static var lock = DispatchSemaphore(value: 1)//value值是几,就表示允许几条线程同时修改
        
        public static func get(_ key:String) -> Any?{
            data[key]
        }
        
        public static func set(_ key:String,_ value:Any){
            lock.wait()
            defer{lock.signal()}
            data[key] = value
        }  
    }
    

    或者:

    import Foundation
    
    public struct Cache{
        private static var data = [String:Any]()
        private static var lock = NSLock()
        
        public static func get(_ key:String) -> Any?{
            data[key]
        }
        
        public static func set(_ key:String,_ value:Any){
            lock.lock()
            defer {lock.unlock()}
            data[key] = value
        }
    }
    

    函数中有递归容易造成死锁,用递归锁解决

    import Foundation
    
    public struct Cache{
        private static var data = [String:Any]()
        private static var lock = NSRecursiveLock()
        
        public static func get(_ key:String) -> Any?{
            data[key]
        }
        
        public static func set(_ key:String,_ value:Any){
            lock.lock()
            defer {lock.unlock()}
            data[key] = value
        }
    }
    

    相关文章

      网友评论

          本文标题:从OC到Swift (二)

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