目录
- 前言
- 核心代码
- class_copyPropertyList
- 在swift3.0以后失效的原因
- 获取类属性的swift的方法代码
- 遍历类属性有什么作用?
- 用一个类来试试哪些属性能被查看
- 调用的代码
- demo代码下载
- 后记
前言
今天是周六休息,在家研究swift的URLNavigator路由框架,因为里面都是用url字符串来打开控制器,这样太不安全了,如果拼写错了,编译也不会报错,只有运行的时候才会发现错误,还得修改第二次url,作为一个懒人,我封装了这个框架,在输入类名的时候直接类名.self就行,拼写的时候xcode回自动提示,拼写错了编译不会通过.但是有一个问题,那就是类名可以进去,但是类的成员变量不能在类创建之前就取出来,所以我找了资料,发现以前的代码返回的属性都是nil,后来发现了问题做了这个demo代码,这样,就可以在封装路由框架的时候使用起来更方便了.
核心代码
class_copyPropertyList
在swift3.0以后失效的原因
这个方法是oc里面的方法,是用的runtime运行时,所以他只能获取到@objc的类属性,因为只有这样的属性,才会被oc的方法找到,这就是为什么这个方法现在获取类属性,都变成nil的原因了.
获取类属性的swift的方法代码
每行代码的作用我在注释里面已经写的很清楚了,首先获取类属性,然后把属性保存起来,用for循环遍历打印出来
/**
获取类属性名字,可以获取带@objc标识的属性名字,因为是用的runtime,所以只能获取@objc的属性,swift特有的属性不能被获取
@param clsType 类名字
*/
func getClassPropertieNames(_ clsType:AnyClass){
var prosCount:UInt32 = 0
//获取属性列表,注意只有@objc的属性,才能被发现,因为class_copyPropertyList是oc的runtime方法
let pros:UnsafeMutablePointer<objc_property_t>! = class_copyPropertyList(clsType.self, &prosCount)
let count:Int = Int(prosCount);
//遍历属性名字
for i in 0..<count {
let pro: objc_property_t = pros[i]
guard let proName:String? = String(cString: property_getName(pro))else{ return }
print("属性名:",proName)
}
free(pros)
}
遍历类属性有什么作用?
可以帮你数据转模型.也就是我们经常用的json转模型,就可以用它.你传入json,然后遍历json数据,然后传入到这个方法里面一个类的对象,然后把对象的属性挨个赋值,例如yyModel,下面是yyModel里面的一段代码,目的就是要把类属性取出来,仔细看是不是跟我们的代码几乎一样?只不过我们用了swift语言
unsigned int propertyCount = 0;
objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
if (properties) {
NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
_propertyInfos = propertyInfos;
for (unsigned int i = 0; i < propertyCount; i++) {
YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
if (info.name) propertyInfos[info.name] = info;
}
free(properties);
}
下面是yyModel在xcode里面的截图
用一个类来试试哪些属性能被查看
下面这个CAModel是一个类的模型,用来存储CA的数据用的,这个不是我们要查看的类
// CAModel.swift
// swiftClassReflectDemo
//
// Created by tdw on 2021/1/23.
//
import UIKit
@objcMembers
//这个是一个模型,用来给CA类保存数据用的,使用情景是解析json的时候,保存json里面的数据
class CAModel: NSObject {
var age:Int = 0
var name:String = ""
var address:String = ""
}
下面这个文件里面有一个结构体Point,一个类CB,一个类CA,其中CA的类名字前面写了@objcMembers,意思是说这个类里面的成员都是被@objc 标记的,可以被查看,但是必须是能转换成oc的类型才能被标记 struct 和 class成员是不能被@objc标记的,所以不能被遍历出来,Double和String这些是可以被@objc标记的,所以可以被遍历出来,代码如下
//
// CA.swift
// swiftClassReflectDemo
//
// Created by tdw on 2021/1/23.
//
import Foundation
struct Point {
var x = 0.0
var y = 0.0
}
@objcMembers
class CB{
var age = 1
}
@objcMembers
class CA {
var item = CAModel() //用来保存模型的类对象也不能遍历查看
var name = "Foo" //String类型,可以被遍历查看
var width:Double = 0
var height:Double = 0
var b = CB() //Class类型,不能被遍历查看
var p = Point() // 结构体类型,不能被遍历查看
var computedPoint : Point { //计算属性,不能被遍历查看
get {
return Point(x: p.x + 100.0, y: p.y - 100.0)
}
}
}
调用的代码
getClassPropertieNames(CA.self)
执行结果打印如下,runtime机制只能遍历出@objc的属性,其他属性oc的方法不能识别:
属性名: Optional(“item”)
属性名: Optional(“name”)
属性名: Optional(“width”)
属性名: Optional(“height”)
demo代码下载
运行代码请使用最新的xcode 12.3版本,否则无法打开
demo代码地址
后记
本来现在疫情健身房关门了,打算在家研究一会代码就在家健身,结果从早上9点半封装路由框架,到了下午为了更方便就研究遍历类属性了,现在8点半了,比上班工作时长还多.但是封装好这个框架以后势必能让以后的工作代码更少,工作更轻松