iOS runtime--获取类信息
在iOS中可以通过runtime获取一个类的相关信息:有哪些方法、有哪些协议、有哪些属性、有哪些成员变量。安排的明明白白,老铁O(∩_∩)O哈哈~
代码语言:javascript复制class_copyMethodList //方法列表
class_copyProtocolList //协议列表
class_copyPropertyList //属性列表
class_copyIvarList //成员变量列表
准备
定义一个Person类继承Human类,一个协议包括两个方法,一个是必须实现的require,一个为可选实现的optional。
代码语言:javascript复制@objc protocol FoodProtocol {
func eat()
@objc optional func drink()
}
class Human: NSObject {
@objc var country: String = ""
}
class Person: Human, FoodProtocol {
@objc private var name: String = ""
@objc private var gender: String = ""
private var age: Int = 26
func eat() {
}
override var description: String {
return String(format: "%@--%@--%@-%d", name, gender, country, age)
}
}
PS:本次demo是在Playground swift实现的,所以有些操作是要加上@objc
在swift中通过NSClassFromString方法获取class时需要这个类所在文件名.类名这样拼接。在Playground中使用以下version充当文件名。
代码语言:javascript复制class Playground : NSObject {
static var bundleVersion: String {
let s = self.description().replacingOccurrences(of: ".Playground", with: "")
return s
}
}
let version = Playground.bundleVersion
class_copyMethodList
根据NSClassFromString获取class,然后获取这个类里面有哪些方法。
代码语言:javascript复制let className = "(version).Person"
var cls = NSClassFromString(className)
var methodCount: UInt32 = 0
let methodList = class_copyMethodList(cls, &methodCount)
for i in 0..<methodCount {
let methodSelector = method_getName(methodList![Int(i)])
debugPrint(methodSelector.description)
}
=============method list====================
".cxx_destruct"
"description"
"name"
"setName:"
"init"
"gender"
"setGender:"
"eat"
class_copyProtocolList
获取Person类遵从了哪些协议,并且查看协议中有哪些方法。(这里我只查看了require 实例方法)
代码语言:javascript复制let className = "(version).Person"
var cls = NSClassFromString(className)
var protocolCount: UInt32 = 0
let protocolList = class_copyProtocolList(cls, &protocolCount)
for i in 0..<protocolCount {
let protocolName = protocol_getName(protocolList![Int(i)])
let protocolKey = String(cString: protocolName)
debugPrint(protocolKey)
var protocolMethodCount: UInt32 = 0
//第一个bool类型:是否是require方法 第二个bool类型:是否是实例方法
let protocolMethodList = protocol_copyMethodDescriptionList(protocolList![Int(i)], true, true, &protocolMethodCount)
for j in 0..<protocolMethodCount {
let method = protocolMethodList![Int(j)]
debugPrint("protocol method: (method.name)")
}
}
=============protocol list====================
"__lldb_expr_34.FoodProtocol"
"protocol method: Optional(eat)"
class_copyPropertyList
这里注意:打印所有属性中是没有age的。这是因为没有加上@objc字段。
代码语言:javascript复制let className = "(version).Person"
var cls = NSClassFromString(className)
var propertyCount: UInt32 = 0
let propertyList = class_copyPropertyList(cls, &propertyCount)
for i in 0..<propertyCount {
let propertyName = property_getName(propertyList![Int(i)])
let key = String(cString: propertyName)
debugPrint(key)
}
=============property list====================
"name"
"gender"
"description"
class_copyIvarList
这里我们打印这个类的所有成员变量,并且也打印出继承的成员变量。使用一个while语句直到NSObject类为止。
发现没有即使是没有给age字段添加@objc,通过成员变量列表也是能获取到的
代码语言:javascript复制let p = Person()
let className = "(version).Person"
var cls = NSClassFromString(className)
while true {
var ivarCount: UInt32 = 0
let ivarList = class_copyIvarList(cls, &ivarCount)//父类的属性不能获取
for i in 0..<ivarCount {
let ivarName = ivar_getName(ivarList![Int(i)])
let key = String(cString: ivarName!)
let value = personDic[key]
debugPrint(key)
}
if let superCls = cls?.superclass(), superCls.self != NSObject.self {
cls = superCls
} else {
break
}
}
=============ivar list====================
"name"
"gender"
"age"
"country"
我们给age添加上@objc,使用setValue:forKey方法直接赋值,最后查看是否赋值成功p.description。这可以用在解析model或者其他地方。
代码语言:javascript复制let personDic = ["name": "joealzhou", "gender": "men", "country": "China", "age": 24] as [String : Any]
let p = Person()
let className = "(version).Person"
var cls = NSClassFromString(className)
while true {
var ivarCount: UInt32 = 0
let ivarList = class_copyIvarList(cls, &ivarCount)//父类的属性不能获取
for i in 0..<ivarCount {
let ivarName = ivar_getName(ivarList![Int(i)])
let key = String(cString: ivarName!)
let value = personDic[key]
debugPrint(key, value)
p.setValue(value, forKey: key)
}
if let superCls = cls?.superclass(), superCls.self != NSObject.self {
cls = superCls
} else {
break
}
}
debugPrint(p.description)
=============ivar list====================
"name" Optional("joealzhou")
"gender" Optional("men")
"age" Optional(24)
"country" Optional("China")
"joealzhou--men--China-24"