swift 如何使用镜像检查对象中的某些属性是否为空?

flvlnr44  于 2023-01-25  发布在  Swift
关注(0)|答案(1)|浏览(217)

假设我有一个类,它有很多属性,我想检查它们中的大多数是否为零...
因此,我只想从该检查中排除两个属性(也就是说,针对20个属性进行检查)。
我试过这样的方法:

extension MyClass {
    func isEmpty() -> Bool {
        
        let excluded = ["propertyName1", "propertyName2"]
        
        let children = Mirror(reflecting: self).children.filter { $0.label != nil }
        
        let filtered = children.filter {!excluded.map{$0}.contains($0.label)}
        
        let result = filtered.allSatisfy{ $0.value == nil }
        
        return result
        
    }
}

关于这段代码,第一件让我烦恼的事情是,如果我改变一个属性名,我将不得不改变被排除的数组值。
但那并不重要,问题是,这一行:

let result = filtered.allSatisfy{ $0.value == nil }

它不会真正检查属性是否为nil ...编译器警告:
将"Any"类型的非可选值与"nil"进行比较始终返回false
那么,有没有更好/适当的方法来解决这个问题?

umuewwlo

umuewwlo1#

Mirror API相当粗糙,Swift的通用反射API还没有设计出来,即使它们已经存在,我也不认为你应该在这种情况下使用它们。
字段全为nil的"空示例"的概念实际上没有意义。想象一下Person(firstName: nil, lastName: nil, age: nil)。你不会有一个"空的人",你有无意义的废话。如果你需要建模nil,使用nillet possiblePerson: Person? = nil
你应该修正你的数据模型。但是如果你现在需要一个解决方案,我有两个想法给你:
∮ ∮只是用无聊的方式∮

extension MyClass {
    func isEmpty() -> Bool {
        a == nil && b == nil && c == nil
    }
}

或者:

extension MyClass {
    func isEmpty() -> Bool {
        ([a, b, c] as [Any?]).allSatisfy { $0 == nil }
    }
}

当然,这两种方法都有缺点,即每当添加新属性时都需要进行更新

中间重构

假设您有:

class MyClass {
   let propertyName1: Int? // Suppose this doesn't effect emptiness
   let propertyName2: Int? // Suppose this doesn't effect emptiness
   let a: Int?
   let b: Int?
   let c: Int?
}

您可以提取出可能为空的部分:

class MyClass {
   let propertyName1: Int? // Suppose this doesn't effect emptiness
   let propertyName2: Int? // Suppose this doesn't effect emptiness
   let innerProperties: InnerProperties?

   struct InnerProperties { // TODO: rename to something relevant to your domain
       let a: Int
       let b: Int
       let c: Int
   }

   var isEmpty: Bool { innerProperties == nil }
}

如果属性a/b/c是您的公共API的一部分,并且您无法轻松更改它们,那么您可以通过添加一些转发计算属性来限制此更改的爆炸半径:

extension MyClass {
    public var a: Int? { innerProperties?.a }
    public var b: Int? { innerProperties?.b }
    public var c: Int? { innerProperties?.c }
}

相关问题