是否可以在运行时在Swift中动态执行深度属性比较?

时间:2016-05-04 16:51:55

标签: swift uikit

假设我们有两个UILabel个实例,对我们来说是等价的:

let label1 = UILabel()
label1.text = "Hello world"

let label2 = UILabel()
label2.text = "Hello world"

假设这两个实例位于[UIView]类型的数组中:

let views: [UIView] = [label1, label2]

有没有办法执行相等性检查,发现这两个UIView实例是等价的,而不知道它们提前是哪种类型(因此要比较哪些常见属性)?

(任何方式使用这些实例都具有dynamicType UILabel的事实,并动态运行UILabel类的键/值属性并比较每个值可以比较?)

发生了什么:

label1 == label2      // false
views[0] == views[1]  // false

满足期望:

areTheSame(label1, label2)     // true
areTheSame(views[0], views[1]) // true

我们正在寻找一种比较两个独立实例的方法,因此我们无法使用===

2 个答案:

答案 0 :(得分:3)

斯威夫特没有反思所以这是不可能的。我们甚至无法获得属性列表。

另请注意,对于许多类型,没有相等的定义。即使比较两个浮点值也是一个问题。

正是由于这个原因,我们有Equatable协议。如果要比较类型,请在它们上定义相等性。然后,这种平等可以根据需要尽可能深入,而不需要任何动态(不安全)行为。

只是为了解释另一个极端情况,例如,在UILabel上有一些您绝对不想比较的属性,即nextRespondersuperview。试图深入比较这些属性实际上会在循环中结束。通常不可能比较两个对象是否相等而不确切知道应该和不应该比较什么。

答案 1 :(得分:2)

这样的事情应该有效:

let views: [UIView] = [label1, label2]

func areTheSameLabel(view1: UIView, _ view2: UIView) -> Bool {
    guard let label1 = view1 as? UILabel,
          let label2 = view2 as? UILabel else { return false }
    return label1.text = label2.text
}

print(areTheSameLabel(label1, label2))  // Should print "true"
print(areTheSameLabel(views[0], views[1]))  // Should print "true"

在回应您的意见时,我认为最好的途径是创建协议:

protocol ViewEquatable {
    var backgroundColor: UIColor? { get set }
    var text: String? { get set }
    // add any other properties you want to compare here...
}

然后编写一个函数来比较它们:

func ==<T: ViewComparable>(lhs: T, rhs: T) -> Bool {
    return (lhs.backgroundColor == rhs.backgroundColor) &&
           (lhs.text == rhs.text) &&
           // whatever other comparison tests you need go here...
}

这样的事情可能是你最好的选择,虽然你的要求太模糊,无法给出完整的答案......