メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックリーディングカンパニーのエンジニアブログです。PHPからRubyへ絶賛移行中!継続的にアウトプットを出し続けられるようにみんなでがんばりまっす!

swift4.1へのバージョンアップとつまづいたこと

こんにちは。メドピアのエンジニアの保立です。
メドピアでは、医師専用コミュニティサイト「MedPeer」のiOSアプリを3月26日にリリースしました。
詳しくはこちら

メドピアのiOSアプリは、swift4.0で開発を始めましたが、先日swift4.1にバージョンアップしたので、今回のブログ記事では、swiftのアップグレードのためにやったことについて紹介します。

swift4.0から4.1の変更点

3月29日にswift4.1がリリースされました。変更内容とメドピアでの対応について記載します。

変更1) SE-0157 Support recursive constraints on associated types (関連する型の再帰的制約をサポート)

変更内容

swift4.0以前では、「プロトコル内で、プロトコル自身を再帰的に参照する」ことを制限していましたが、swift4.1以降では、その制限が解除されました。

// swift4.0以前では、コンパイルエラーとなる
protocol Sequence {
    // `SubSequence` が、再帰的に `Sequence` を参照している
    associatedtype SubSequence: Sequence
        where Iterator.Element == SubSequence.Iterator.Element, SubSequence.SubSequence == SubSequence

    func dropFirst(_ n: Int) -> Self.SubSequence { ... }
}

ちなみに、swift4.0以前では以下のように実装する必要がありました。わかりづらい。。。

protocol Sequence {
    associatedtype SubSequence

    func dropFirst(_ n: Int) -> Self.SubSequence { ... }
}

struct SequenceOfInts : Sequence {
    func dropFirst(_ n: Int) -> SimpleSubSequence<Int> { ... }
}

struct SimpleSubSequence<Element> : Sequence {
    typealias SubSequence = SimpleSubSequence<Element>
    typealias Iterator.Element = Element
}
対応

プロトコル内でassociatedtype を使って再帰的に参照している箇所を修正。

変更2) SE-0185 Synthesizing Equatable and Hashable conformance (EquatableとHashable適合性の合成)

swift4.1化のメインで、最もメリットを享受できる変更だと思います。

変更内容

Equatable / Hashable プロトコル内に実装する必要があった決まり文句を、暗黙的に実装してくれるようになりました。

struct Question: Equatable {
    let id: Int64
    let title: String

    // swift4.1以降では、 '==' の実装が不要になる。便利!
    public static func == (lhs: Question, rhs: Question) -> Bool {
        return lhs.id == rhs.id && lhs.title == rhs.title
    }
}

今までは、public static func == (lhs: Element, rhs: Element) -> Bool { ... } を明示する必要があったため、プロパティの追加、削除、または変更があった場合、この演算子を更新しなければならないことと、手作業で記述する必要があるため、漏れや誤植で間違ってしまう可能性がありました。
Hashable の場合、以下のようになります。

struct ForumTag: Hashable {
    let id: Int64
    let name: String

    // swift4.1以降では、 '==' も 'var hashValue: Int{} ` も実装が不要になる。超便利!!
    var hashValue: Int {
        return id.hashValue
    }

    static func == (lhs: ForumTag, rhs: ForumTag) -> Bool {
        return lhs.id == rhs.id
    }
}
対応

Equatable / Hashable プロトコルに実装された ==hashValue を使うように修正。

変更3) SE-0187 Introduce Sequence.compactMap(_:) (Sequence.compactMap(_:)の導入)

変更内容

Sequence.flatMap を廃止し、 同じ機能として、 compactMap(_:) を導入する。

対応

コンパイルエラーになったら対応。(MedPeerアプリでは Sequence.flatMap を使っている箇所はありませんでした)

変更4) SE-0188 Make Standard Library Index Types Hashable (標準ライブラリのインデックス型をHashableに)

変更内容

swift4から KeyPath という機能が実装されました。 KeyPath については Qiita が参考になると思います。

対応

MedPeerアプリでは、KeyPath使ってないので対応不要。

(おまけ) SE-0143 Conditional Conformance (条件付き適合)

この変更は、swift4.2以降で実装されます。

変更内容

URL: https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md

型引数が特定の要件を満たす場合にのみ、ジェネリック型が特定のプロトコルに準拠するという概念を表現できるようにします。

例えば、Array に対して、その要素がEquatableである場合に、Equatableプロトコルを実装することができることを表したい時、以下のように実装します。

extension Array: Equatable where Element: Equatable {
  static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}

swift4.1以前で、上記のような実装をすると、「 'Array' 自体がEquatableでない」という理由で、コンパイルエラーになります。

error: extension of type 'Array' with constraints cannot have an inheritance clause
extension Array: Equatable where Element: Equatable { }
^                ~~~~~~~~~

これが解決されます。 Standard Library Adoption に記載されている通り、 OptionalArrayEncodable / Hashable 適合など、既存のライブラリにはすでに内部で使われています。

swift4.1に移行する時につまづいたこと

swift4.1への移行はほぼスムーズにできましたが、1点だけ修正が面倒なことがありました。Firebaseなどのサードパーティーツールで、以下のようなWarningが出ることです。

/path-to-app/vendor/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics: Failed to parse executable: Unknown header: 1918975009

メドピアでは、ライブラリ管理にCarthageを使っていたのですが、FirebaseなどはCocoaPodsにのみ対応していたので、FirebaseSDKを直接ダウンロードしていました。それにより、Firebaseのバージョン管理が適切にできていないのが原因でした。
結局、Carthageで管理できないライブラリは、CocoaPodsで管理することで解決しました。 この修正により、以下のライブラリをCocoaPodsで管理するように修正しています。

- Firebase/Core
- Fabric
- Crashlytics
- Repro
- R.swift

まとめ

今回、メドピアでは初めてswiftのバージョンアップを実施しましたが、今後もバージョンアップ等で得た知見をブログに執筆していきます。
iOSアプリはまだリリースしたばかりで、開発したいこと/すべきことが山ほどあるので、メドピアに少しでも興味を持っていただけたら遊びに来てほしいです。


是非読者になってください(ง `ω´)ง


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら

https://medpeer.co.jp/recruit/entry/

■開発環境はこちら

https://medpeer.co.jp/recruit/workplace/development.html