类的属性前面需要加上@objc关键词或者类前面加上@objcMembers ,否则运行时访问不了类的属性
原因:在Swift 4中继承 NSObject 的 swift class 不再默认全部 bridge 到 OC,如果我们想要使用的话我们就需要在class前面加上@objcMembers 这么一个关键字。
引用: 在 swift 3 中除了手动添加 @objc 声明函数支持 OC 调用还有另外一种方式:继承 NSObject。class 继承了 NSObject 后,编译器就会默认给这个类中的所有函数都标记为 @objc ,支持 OC 调用。苹果在Swift 4 中苹果修改了自动添加 @objc 的逻辑:一个继承 NSObject 的 swift 类不再默认给所有函数添加 @objc。只在实现 OC 接口和重写 OC 方法时才自动给函数添加 @objc 标识。
import UIKit
//需要加上@objcMembers 这么一个关键字。
@objcMembers class Student: NSObject {
var name :String?
var age : Int = 18
var title = "I like League of legend"
var a:String?
///[使用运行时]获取当前类所有的属性数组
class func propertyList() -> [String] {
var count :UInt32 = 0
//获取‘类’的属性列表
let list = class_copyPropertyList(self, &count)
print("属性的数量\(count)")
for i in 0..<Int(count) {
//根据下标 获取属性
let a = list?[i]
//获取属性的名称
let cName = property_getName(a!)
let n = String(utf8String:cName)
print(cName)
print(n as Any)
print("hhh")
}
/*
// - 使用 guard let 守护,依次判断每一项是否有值,
// - 只要有一项为nil,就不在执行后续的代码
for i in 0..<Int(count) {
guard let pty = propertyList?[i],
let cName: UnsafePointer<Int8> = property_getName(pty),
let pName = String(utf8String: cName) else {
//继续下一个
continue
}
print(pName as Any)
}
*/
return [];
}
}
注:之前用KVC赋值时就遇到过这个问题,原因同上;
KVC赋值
import UIKit
//在Swift 4中继承 NSObject 的 swift class 不再默认全部 bridge 到 OC,
//如果我们想要使用的话我们就需要在class前面加上@objcMembers 这么一个关键字。
@objcMembers class Person: NSObject {
var name: String?
var age: Int = 0
var title: String?
init(dict: [String: Any]) {
super.init()
setValuesForKeys(dict)
}
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(Person.propertyList())
let p = Person(dict: ["name" : "Any"])
print(p.name as Any)
}
}
OC 运行时访问类的属性:
unsigned int count;
objc_property_t *propertyList = class_copyPropertyList(self, &count);
for (unsigned int i = 0; i<count; i++) {
//根据下标 获取属性
objc_property_t property = propertyList[i];
//获取属性的名称
const char *ptyName = property_getName(property);
//char 转 NSString数据类型
NSString *pName = [NSString stringWithUTF8String:ptyName];
NSLog(@"属性是:%@",pName)
}
free(propertyList);