Swift Utilities — Equatable для сложных Enum

от автора

За годы работы разработчиком iOS, я собрал множество инструментов и полезных штук, которые облегчают процесс разработки. В этой статье, я хочу поделиться одним из таких инструментов. Это будет не большая статья. Я покажу, как пользоваться этой утилитой, продемонстрирую её в действии. Надеюсь, что статья окажется полезной для вас.

Мне часто встречалась ситуация когда надо подписать enum со вложенными типами под протокол Equatable и приходилось реализовывать его функции

static func ==(lhs: T, rhs: T) -> Bool

Чтобы упростить жизнь и каждый раз не писать сложные static func ==(lhs: T, rhs: T) -> Bool Можно подписать enum под protocol ComplexEquatable

/// ```swift /// enum SomeState: ComplexEquatable { ///     case text(SomeText) /// } /// /// class SomeText { ///     var text: String? /// ///     init(text: String?) { ///         self.text = text ///     } /// } /// /// let objectOne = SomeState.text(.init(text: nil)) /// let objectTwo = SomeState.text(.init(text: "Hello, World!")) /// objectOne == objectTwo // false /// /// let objectOne = SomeState.text(.init(text: "Hello, World!")) /// let objectTwo = SomeState.text(.init(text: "Hello, World!")) /// objectOne == objectTwo // true /// /// let objectOne = SomeState.text(.init(text: "Hello")) /// let objectTwo = SomeState.text(.init(text: "Hello, World!")) /// objectOne == objectTwo // false /// ``` public protocol ComplexEquatable: Hashable, Equatable {}  extension ComplexEquatable {      static func == (lhs: Self, rhs: Self) -> Bool {         lhs.hashValue == rhs.hashValue     }      func hash(into hasher: inout Hasher) {         hasher.combine(getObjectInfo(of: self))     }      private func getObjectInfo(of instance: Any) -> String {         let mirror = Mirror(reflecting: instance)         var result = ""          for (index, child) in mirror.children.enumerated() {             if let propertyName = child.label {                 result += "\(index == 0 ? "" : ",")\(propertyName):\(child.value)"                 let childString = getObjectInfo(of: child.value)                 if !childString.isEmpty {                     result += "{\(childString)}"                 }             }         }         if result == "" {             return String(describing: instance)         }         return result     } } 

Сердцем ComplexEquatable является метод getObjectInfo, использующий Mirror для рефлексии объектов. Этот метод позволяет исследовать структуру объекта и генерировать уникальное хэш-значение, основываясь на всех его свойствах. Это ключ к тому, чтобы два объекта, идентичные по структуре и содержанию, считались одинаковыми.

Пример использования

Рассмотрим несколько примеров для enum.

enum SomeState: ComplexEquatable {      case text(SomeText)  }  class SomeText {     var text: String?      init(text: String?) {         self.text = text     } }

Когда мы сравниваем два объекта SomeState, содержащих nil и строку «Hello, World!» соответственно, результатом будет false, так как их содержимое различно.

let objectOne = SomeState.text(.init(text: nil)) let objectTwo = SomeState.text(.init(text: "Hello, World!")) objectOne == objectTwo // false

Однако, если сравнивать два объекта с одинаковыми строками «Hello, World!», результатом будет true. Это демонстрирует гибкость ComplexEquatable в различных сценариях сравнения.

let objectOne = SomeState.text(.init(text: "Hello, World!")) let objectTwo = SomeState.text(.init(text: "Hello, World!")) objectOne == objectTwo // true

Еще статьи Swift Utilities:


ссылка на оригинал статьи https://habr.com/ru/articles/774894/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *