Swift における「defer」について…

朝の実(Asanomi)アイコン アプリ開発

Swift で処理を書いていると、
「この処理は、成功しても失敗しても、最後に必ず実行したい」
という場面が出てきます。

こうした、最後に必ず実行したい処理を
コード上で設計として表現できるのが、
Swift の defer です。

この記事では、この defer がどのような構文なのかを解説していきます。

defer とは?

defer は、
その defer が書かれているスコープを抜ける直前に実行される処理を定義するための構文です。

以下、defer の書き方です。

defer {
    // この中に、スコープの終了時に必ず実行したい処理を記述する
}

実際にいつ実行されるかは、
この defer が書かれているスコープによって決まります。

defer の処理されるタイミング

defer の中の処理は、
その defer を含むスコープの最後で実行されます。

ここで重要なのは、
「関数の最後」とは限らない、という点です。

defer は、
書かれた場所のスコープに紐づいて動作します。

if 文との兼ね合い

公式ドキュメントでは、
if 文と defer の関係を示す例が紹介されています。

func f(x: Int) {
    defer { print("First defer") }

    if x < 10 {
        defer { print("Second defer") }
        print("End of if")
    }

    print("End of function")
}

f(x: 5)

このコードを実行すると、出力は次の順になります。

End of if
Second defer
End of function
First defer

この結果から分かるのは、
defer は「関数の最後にまとめて実行される」わけではない、ということです。

それぞれの defer は、
自分が属しているスコープが終了するタイミングで実行されています。

この例では、

  • if 文のスコープが先に終了する
  • 関数全体のスコープはその後に終了する

という流れになるため、
if 文内の defer が先に実行され、
関数スコープの defer は最後に実行されます。

実際の使用例(朝の実)

私が現在開発中の朝専用SNSアプリ「朝の実」では、
投稿処理の実装において defer を使用しています。

投稿処理では、

  • 投稿中であることを示すフラグを立てる
  • そのフラグは成功・失敗に関わらず、最後に必ず元に戻す

という要件があります。

@MainActor
final class PostViewModel: ObservableObject {

    @Published var text: String = ""
    @Published var isPosting: Bool = false
    @Published var errorMessage: String?

    func post() async {
        let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else {
            errorMessage = "本文を入力してください"
            return
        }

        // 処理開始時にフラグを立てる
        isPosting = true

        // スコープ終了時に必ずフラグを戻す
        defer {
            isPosting = false
        }

        do {
            try await saveToCloudKit(text: trimmed)
            text = ""
        } catch {
            errorMessage = "投稿に失敗しました"
        }
    }

    private func saveToCloudKit(text: String) async throws {
        // CloudKit への保存処理(省略)
    }
}

defer を使うことで、
「必ずフラグを戻す」という意図を、
分岐に関係なく 1 か所にまとめて表現できます。

まとめ

defer は、単なる便利構文ではなく、
最後に必ず実行したい処理を設計として切り出す」という意図を明確にできます。

スコープと実行タイミングを正しく理解することで、
非同期処理やエラー処理を含むコードでも、
意図の伝わる、安全な実装につながると考えています。

sho shimizu

SwiftUI を用いたiOS アプリの個人開発を行っています。
これまでに2本のアプリを App Store にリリースしました。

現在は、朝専用SNS「朝の実(Asanomi)」を開発中です。
CloudKitやSwift Concurrencyを用いた実装を進めながら、
設計や実装上で整理した内容を技術記事にまとめています。

sho shimizuをフォローする
アプリ開発技術解説朝の実
シェアする
sho shimizuをフォローする