swfit进阶-09-swift中的runtime

215 阅读3分钟

「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。

  • 本文主要介绍swift中如何使用runtime

1. 回顾OC中runtime

  1. 什么是runtime 在OC中runtime本质是底层的c,c++,汇编组成的API。将我们编译时确定的数据类型推迟到运行时确定,我们平时编写的OC的代码,需要用runtime创建类和对象,进行消息发送转发,最终都会转换为runtimec语言代码

  2. 为什么使用runtime?

  • oc是一门动态语言,主要体现在以下3个方面,因此需要运行时系统来处理编译后的代码
    • 动态类型:运行时确定对象的类型
    • 动态绑定:运行时确定对象的调用方法
    • 动态加载:运行时加载需要的资源或者可执行代码
  • runtime基本是用C语言和汇编语言写的,苹果和GNU各自维护一个开源的runtime版本,这两个版本之间都高度的保持一致
  1. runtime有什么用?
  • 进行方法交换 (method swizzling)
  • 给分类添加属性
  • 动态的注册,创建一个类以及销毁
  • 消息的发送和转发
  • 访问私有变量
  • 模型转数组

2. swift中runtime

我们定义一个swift类,并定义它的方法和属性,之后通过我们在oc中获取方法列表和属性列表的方式打印

class Person {

    

    var name = "jack"

    

    func sleep()  {

        print("sleep")

    }

    

}

do{


    var methodCount:UInt32 = 0

    let methodList = class_copyMethodList(Person.self, &methodCount)

    for i in 0..<numericCast(methodCount){

        

        if let method = methodList?[i] {

            let  methodName = method_getName(method)

            print("methodName is \(methodName)")

            

            

        }else{

            print("not found method");

        }

    }

    var properCount:UInt32 = 0

    let proList = class_copyPropertyList(Person.self, &properCount)

    for i in 0..<numericCast(properCount){

        

        if let property = proList?[i] {

            let propertyName = property_getName(property)

            

            print("propertyName is \(propertyName)")

            

        }else{

            print("not found property");

        }

    }   

}

image.png

最后什么也没打印,说明无法获取到,如果我们添加@objc在属性和方法前面,是否就具备了运行时的特性

image.png

就打印出来了,但是没有暴漏给oc,所以oc是无法使用的,这样做是没有意义的

image.png

没有任何关于Person的信息

image.png

  • 我们把类继续NSObject ,并把@objc去除

image.png

只有析构方法,此时暴漏出来的只有init方法,有.cxx_destruct是因为我们的nameString类型一个对象。

image.png

我们换成常量的话就没有cxx_destruct

image.png

查看提供给oc的方法只有init

  • 我们要提供给oc使用需要继承NSObject,同时属性和方法使用@objc修饰

image.png

  • 我们把@objec 换成dynamic,还是不行

image.png

  • 我们使用@objc dynamic进行修饰即可

image.png

3.结论

  1. swift是一门静态语言,而oc是动态语言,所以纯swift类是不具有runtime特性。是通过前面讲的方法调度:静态派发动态派发
  2. 对于纯swift类,我们使用@objc修饰后的方法和属性具备了runtime特性,但是我们的oc中无法进行调度,只能swift中使用。
  3. 对于继承NSObjectswift类,我们想要动态的获取属性和方法需要在属性和方法前面修饰@objc,否则也不具备runtime特性。
  4. 对于继承自NSObject类来说,如果想要动态的获取当前属性+方法,必须在其声明前添加 @objc关键字,如果想要使用方法交换,还必须在属性+方法前添加dynamic关键字,否则当前属性+方法只是暴露给OC使用,而不具备任何动态特性
  5. 若方法的参数或者属性类型为swift特有的,无法映射oc中的(比如TupleCharacter),则此方法的属性或者方法无法添加dynamic修饰(编译器报错)