Swiftでのdoの使われ方


はじめに

Swiftで調べ物をしているとdoが急に出てきて公式レファレンスにも特に言及がなく困ったりしたので簡単に整理します。

  1. do-catch文(エラーハンドリング)
  2. do文(catch無し)
  3. do while -- swift2以降はrepeat whiile
  4. 番外編:RxSwiftで副作用を記述する

1.do-catch文

doの下にcatchがあればエラー処理構文です。


// 例外(エラー)を持ちうるメソッド
func eee() throws {
...
}

// 呼び出し元
func method() {
    do {
        try? eee()
    } catch {
        // エラー処理
    }
}

まずエラーも持ちうるメソッドをthrowsキーワードを付けて記述します。
それをdoのスコープ内でtryキーワードを付けて呼んであげると、エラー時にcatchスコープで捕捉できるというアレです。
これは一番オーソドックスなので調べればいくらでも情報が出てくると思います。
レファレンスも充実しているのでそちらをどうぞ。

2.do文(catch無し)

むしろ困るのはcatch無しで登場した場合ではないでしょうか。
調べてもdo-catchばかりで「お前はもういいよ!」となっているのでは?(私はそうでした)

これも文法的にはdo-catchのcatchが無いだけで、別概念というわけではないようです。
しかし、用法は異なり、スコープという機能そのものを使いたいときによく利用されるようです。

例えばスコープ内で定義した変数はその中のみで有効です。なので実行が終わればそのインスタンスは解放されるはずです。
その解放をPlayground等で確認するため使われたりします。
簡単な例です。

class Prof {

    let name: String

    init(name: String) {
        self.name = name
        print("init:" + self.name)
    }

    deinit {
         print("deinit:" + self.name)
    }
}

let prof = Prof(name: "Tarou")

do {
    let profInDo = Prof(name: "Jirou")
}

結果

init:Tarou
init:Jirou
deinit:Jirou

インスタンス化しただけのprofは当然解放されません。
しかし、doのスコープに入れたprofInDoはdeinitまで呼ばれているのが確認できます。
このように手っ取り早くスコープを使うためにdoを使います。

do-while

これはSwift1.2までの記法で、Swift2以降はrepeat whileとなります。
repeat while自体あまり使わない(偏見)のでこれでつまる人はまずいないでしょう(偏見)。

番外編:RxSwiftで副作用を記述

多くの現場で使われているRxのライブラリであるRxSwiftのオペレータにもdoは存在します。
弊社のプロジェクトでも無数に使われています。
observableが発行するイベントとは別に、何らかの処理を記述したい場合に使います。

定義


    public func `do`(onNext: ((Self.Element) throws -> Void)? = nil, afterNext: ((Self.Element) throws -> Void)? = nil, onError: ((Error) throws -> Void)? = nil, afterError: ((Error) throws -> Void)? = nil, onCompleted: (() throws -> Void)? = nil, afterCompleted: (() throws -> Void)? = nil, onSubscribe: (() -> Void)? = nil, onSubscribed: (() -> Void)? = nil, onDispose: (() -> Void)? = nil) -> RxSwift.Observable<Self.Element

以上になります。
誤りや他の用法がありましたらご指摘くださいませ。
参考:詳解Swift第5版