【swift】RxDataSourcesでEquatableに準拠せさるときに!


はじめに

RxSwiftで、TableViewの差分更新を行うときに、RxDataSourcesを使うことがあると思います。
RxDataSorcesの詳細に関しては、公式レポジトリーを参照してださい....

RxDataSources

RxTableViewSectionedAnimatedDataSourceを使う場合、AnimatableSectionModelTypeに準拠したmodelを用意する必要があります。
実装としては
1. RxTableViewSectionedAnimatedDataSourcecellsectionなどのtableViewの設定をAnimatableSectionModelTypeに準拠したmodelを用いて行う
2. AnimatableSectionModelTypeに準拠したObservablemodeltableViewbindする

詳細はサンプルコードをみてください。(RxDataSources/Example/Example1_CustomizationUsingTableViewDelegate.swift

Equatableへの準拠

上記の実装のように、RxDataSourcesを使うにはAnimatableSectionModelTypeに準拠したmodelを用意する必要があり、準拠するAnimatableSectionModelTypeのprotocolは下記のようになっています。

AnimatableSectionModelType.swift
public protocol AnimatableSectionModelType {
    : SectionModelType
    , IdentifiableType where Item: IdentifiableType, Item: Equatable {
}

また、AnimatableSectionModelTypeが準拠しているSectionModelTypeは下記の実装になっています。

SectionModelType.swift
public protocol SectionModelType {
    associatedtype Item

    var items: [Item] { get }

    init(original: Self, items: [Item])
}

SectionModelTypeのGenericsのItemIdentifiableTypeEquatableに準拠する必要があります!!

困ったこと:Equatableに準拠できない!?

NSObjectに準拠したmodelをEquatableに準拠させようとしていた。。。

sample.swift
class TestModel: NSObject { 
    let id: Int
}

extension TestModel: Equatable {
    static func == (lhs: TestModel, rhs: TestModel) -> Bool {
        return lhs.id == rhs.id
    }
}

下記のコンパイルエラーがでる
Redundant conformance of 'TestModel' to protocol 'Equatable'

自作したクラスTestModelEquatableに準拠したつもりはないのに、なぜ準拠済みなのかわからない??

理由:NSObjectがすでにEquatableである!

NSObjectのドキュメントのConformsにあるように、NSObjectはすでにEquatableに準拠しています。そのため、上記の実装だと既に準拠だとエラーが出ます。
ちなみに、NSObjectEquatableは参照しているポインタが同じかどうかをチェックしています。

superクラスの比較でなく、subclassを用いて比較させたい場合は、subclassにクラスメソッドを実装することで、subclassでの比較を行うことができます。

extension TestModel {
    static func ==(lhs: TestModel, rhs: TestModel) -> Bool {
        return lhs.id == rhs.id
    }
}

swift4.1からのEquatable

ここからは上記のエラーとは異なりますが、Equatableなクラスを実装するときの追加の話です。
swift4.1からは、より簡単にEquatableの実装を行うことができます。

swift4.1で実装されたSynthesizing Equatable and Hashable conformanceによって、コンパイラーが自動的にEquatableHashableに準拠させてくれます。

条件としては、
Equatableの実装するクラス or enum or structで定義されているstored instance propertyassociated valueが、Equatableに準拠している場合に、static func == (lhs: Self, rhs: Self) -> Boolが暗黙的に実装されます。

実装例が下記になります!
swift4.0の場合

test.swift
struct Person: Equatable {
    let firstName: String
    let lastName: String

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName &&
               lhs.lastName == rhs.lastName &&
    }
}

swift4.1の場合(暗黙的にEquatableに準拠できる!!)

test.swift
struct Person: Equatable {
    let firstName: String
    let lastName: String
}

上記のようにEquatableに準拠する際に、大量のコードを記述する必要がなくなって、よりEquatableが使いやすくなり、RxDataSourcesも使いやすくなったと思います!!!