runtime

runtime遍历所有属性

2018-10-01  本文已影响16人  轻云绿原

这段时间做征收平台项目,其中有个需求是比较两个类之间所有的属性是否相等,前几天做的是如下

class A:NSObject {
    var a:String
    var b:Int
    var c:Date
    .
    .
    .
    //有几十个var,要疯了

    static func == (lhs:A,rhs:A) -> Bool {
        return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.b ....//好无聊阿,浪费时间
    }
}

大问题:是这样的class, 有几十个......

有没有其它方法,可以懒一些,

runtime

思路

我们可以用runtime遍历这样的类的属性,再把属性值给取出来做比较.

0. 原料:

class TestObj:NSObject {
    var str:String = "string"
    var number:Int = 34343
    var date:Date = Date()
    var list:[String] = ["d","f"]
    
    init(date:Date) {
      self.date = date
      super.init()
    }
}

1.首先要把类中的属性拿出来

var count:UInt32 = UInt32.max  //这里用来保存类中有几个可拿的属性
let firstPropertyPointer = class_copyPropertyList(TestObj.self,&count)
// firstPropertyPointer,就是数组一样指向第一个属性的地址

把count 打印出来看看.
然后看到的是

"0" .....

咋回事?
原来是runtime只在objective-c里生效,那把所有属性加上@objc

class TestObj:NSObject {
    @objc var str:String = "string"
    @objc var number:Int = 34343
    @objc var date:Date = Date()
    @objc var list:[String] = ["d","f"]
    
    init(date:Date) {
      self.date = date
      super.init()
    }
}

再打印count看一下,
现在看到

"4"

正常了.

2.可以遍历一样属性了,看看

for i in 0 ..< count {
    let pointer  = firstPropertyPointer.advanced(by:Int(i))//得到属性的指针(地址)
    let property = pointer.move()//得到property,(地址指向的值)
    let name = String(cString:property_getName(property))//得到属性的名字
}

这样就可以打印出这个类里标有@objc的所有属性的名字了

3.再向下就是得到值了

let obj = TestObj(date:Date())
obj.value(forKey:name)

4.比较

let value = obj.value(forKey:name)

这个value出来的是Any?,不能直接比较.所有objective-C里的都是类,是类就是继承至NSObject,那这样的话就可以如下写

let value = obj.value(forKey:name) as! NSObject

5.综合

class TestObj: NSObject {
     @objc var obj:String = "fd"
     @objc var number:Int = 12312
     @objc var date:Date = Date()
     @objc var list:[String] = ["d","f"]
    
    init(date:Date){
        super.init()
        self.date = date
    }
    static func == (lhs:TestObj,rhs:TestObj) -> Bool{
        var count:UInt32 = UInt32.max
        guard let firstPropertyPointer = class_copyPropertyList(TestObj.self, &count) else{
            return false
        }
        for i in 0 ..< count {
            let propertyP = firstPropertyPointer.advanced(by: Int(i))
            let property = propertyP.move()
            let propertyName = String(cString:property_getName(property))
            let lValue = lhs.value(forKey: propertyName) as! NSObject
            let rValue = rhs.value(forKey: propertyName) as! NSObject
            if lValue != rValue {
                return false
            }
        }
        free(firstPropertyPointer)//释放内存,这是C语言层面的,不会自动释放内存
        return true
    }
}
上一篇 下一篇

猜你喜欢

热点阅读