Допустим, у нас есть два экземпляра 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

Мы ищем способ сравнить два отдельных экземпляра, поэтому мы не можем использовать ===.

1
sahandnayebaziz 4 Май 2016 в 19:51

2 ответа

Лучший ответ

Swift не имеет отражения, поэтому это невозможно. Мы даже не можем получить список атрибутов.

Также обратите внимание, что для многих типов нет определения равенства. Даже сравнение двух значений с плавающей запятой является проблемой.

Именно поэтому у нас есть протокол Equatable. Если вы хотите сравнивать типы, определите для них равенство. Это равенство может быть настолько глубоким, насколько необходимо, без необходимости какого-либо динамического (небезопасного) поведения.

Просто чтобы объяснить другой угловой случай, например, для UILabel есть некоторые свойства, которые вы определенно не хотите сравнивать, а именно такие вещи, как nextResponder или superview. Попытка глубокого сравнения этих свойств фактически закончится циклом. Обычно невозможно сравнить два объекта на равенство, не зная точно, что следует и что не следует сравнивать.

3
Sulthan 4 Май 2016 в 18:41

Примерно так должно работать:

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...
}

Что-то подобное, вероятно, ваш лучший вариант, хотя ваши требования слишком расплывчаты, чтобы дать исчерпывающий ответ ...

2
Aaron Rasmussen 4 Май 2016 в 18:36