美文网首页
从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