Swift调用Objective-C的Runtime
首先,我们来测试一下使用Swift代码来调用Objective-C Runtime的方法,首先创建两个类,用来做对比,一个是纯的Swift类,另一个继承自NSObject:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 //纯Swift类 class SwiftClass { var aBool = true var aInt = 3 var aStrig = "sss" var aObject :AnyObject? func swiftTest() { } } //继承自NSObject的类 class SwiftWithOCClass :NSObject{ var aBool = true var aInt = 3 var aStrig = "sss" var aObject :AnyObject? func swiftTest(aCharacter:Character) { } func justTest() { } }
接下来,我们来创建一个方法,用来获取Class的方法和属性,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func getMethodListAndProperties(cls:AnyClass) -> Void { var methodCount:UInt32 = 0 let methodList = class_copyMethodList(cls, &methodCount) //打印方法 for i in 0..<Int(methodCount) { let method = methodList[i] print(String(UTF8String:method_getTypeEncoding(method))) print(String(_sel:method_getName(method))) } free(methodList) var propertiesCount:UInt32 = 0 let propertiesList = class_copyPropertyList(cls, &propertiesCount) //打印属性 for i in 0..<Int(propertiesCount) { let property = propertiesList[i] print(String(UTF8String:property_getName(property))) print(String(UTF8String:property_getAttributes(property))) } free(propertiesList) }
当调用getMethodListAndProperties(SwiftWithOCClass)
方法时,其打印结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 //打印的方法 Optional("B16@0:8") aBool Optional("v20@0:8B16") setABool: Optional("q16@0:8") aInt Optional("v24@0:8q16") setAInt: Optional("@16@0:8") aStrig Optional("v24@0:8@16") setAStrig: Optional("@16@0:8") aObject Optional("v24@0:8@16") setAObject: Optional("v16@0:8") justTest Optional("@?") .cxx_destruct Optional("@16@0:8") init //打印的属性 Optional("aBool") Optional("TB,N,VaBool") Optional("aInt") Optional("Tq,N,VaInt") Optional("aStrig") Optional("T@\"NSString\",N,C,VaStrig") Optional("aObject") Optional("T@,N,&,VaObject")
当调用getMethodListAndProperties(SwiftClass)
方法时,我们发现并没有打印结果,既没有获取到纯Swift类的属性和方法;而继承自NSObject
的类SwiftWithOCClass则能够获取到属性和方法,翻阅官方文档(如下图),我们就能找到原因,通过继承NSObject
,对象可以拥有运行时且可以被看成Objective-C对象。
我们不禁要问,对于纯Swift类,难道就没有办法使用Objective-C运行时了么?答案是否定的,我们可以使用dynamic
修饰符,实验一下,在纯Swift类的属性aBool中加入dynamic
修饰符,代码如下,我们发现,可以通过运行时找到aBool属性的两个访问器方法以及属性名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class SwiftClass { dynamic var aBool = true var aInt = 3 var aStrig = "sss" var aObject :AnyObject? func swiftTest() { } } //打印结果 Optional("B16@0:8") aBool Optional("v20@0:8B16") setABool: Optional("aBool") Optional("TB,N,VaBool")
而当调用getMethodListAndProperties(SwiftWithOCClass)
时,大多数方法都打印出来了,但有一个方法没获取到,为func swiftTest(aCharacter:Character)
,原因是该方法的参数是Character类型,它是Swift特有的,无法转化(Bridge)为OC的类型,所以无法通过运行时获取到该方法。
load方法
在使用Objective-C的Runtime时,经常会用到Method Swizzling技术,该技术通常在load
方法中实现。而在Swift中不允许定义load
方法,否则编译器会报错,所以,如果要实现Method Swizzling,有几种解决方案:
在initialize
中来实现,但是需要注意的是initialize
可能会被调用多次,所以需要在initialize
实现中做一些判断,比如判断是否是当前类,而不是子类,使用dispatch_once
来进行操作。
在App Delegate中实现Method Swizzling:在AppDelegate的 application(_:didFinishLaunchingWithOptions:)
方法中进行Method Swizzling。