目录

  • 前言
  • 核心代码
  • 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里面的截图

swift 通过路径获取data swift遍历_swift 通过路径获取data

用一个类来试试哪些属性能被查看

下面这个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点半了,比上班工作时长还多.但是封装好这个框架以后势必能让以后的工作代码更少,工作更轻松