問題の歴史:
DeferはSwiftに追加され(GoやC#の類似からインスパイアを受けて)、エラー発生時や関数からの戻り値が異なるポイントでの戻りの際にも、リソースのクリーンアップを保証します。
問題:
早すぎる解放、リソースのクリーンアップの忘れ(ファイルのクローズ、ロギング、トランザクションのロールバックなど)。時には実行順序を混同し、deferが宣言時に実行されると思い込むことがあります。
解決策:
Deferは特別なブロックで、現在のスコープ(通常は関数)の終わりまでコードの実行を遅延させます。すべてのdeferは、配置の逆順(LIFO)で実行されます。これにより、リソースのクリーンアップ、メモリの解放、またはトランザクションのロールバックを集中管理できます。
コード例:
func processFile() { let file = File("/tmp/data.txt") file.open() defer { file.close() print("ファイルを閉じました") } // ファイルでの作業 print("データを読み込んでいます…") }
主な特徴:
アプリがクラッシュする前にdefer内のコードは実行されますか?
いいえ、deferのコードはスコープからの正常な出口時にのみ実行されます。アプリが異常終了(例えば、致命的なエラー)の場合、deferは実行されません。
defer内でreturnを使用できますか?
いいえ、できません。Deferブロックでは値を返したりスコープを終了することはできず、命令のみが許可されます。
deferはdeferより前に宣言された変数を変更するために使用できますか?
はい、deferは実行時に現在のスタックの値をキャッチします。deferの前に宣言された値を変更することができ、スコープを出る際に保持されます。
コード例:
func example() -> Int { var result = 0 defer { result = 42 } return result // deferが実行され、結果は42 }
ファイルが開かれますが、関数の最後で明示的にクローズされ、エラーや関数からの早期退出でファイルが開いたままになります。
利点:
欠点:
ファイルを開いた直後にdeferを使用してファイルを閉じます。例外が発生したり関数から戻ったりしても、ファイルは必ず閉じられます。
利点:
欠点: