ProgrammingiOS/Swift 開発者

Swiftにおけるdefer文とは何ですか?実行の特徴、どこで使うのが適切で、どのような落とし穴があるか教えてください。

Hintsage AIアシスタントで面接を突破

回答。

問題の歴史:

DeferはSwiftに追加され(GoやC#の類似からインスパイアを受けて)、エラー発生時や関数からの戻り値が異なるポイントでの戻りの際にも、リソースのクリーンアップを保証します。

問題:

早すぎる解放、リソースのクリーンアップの忘れ(ファイルのクローズ、ロギング、トランザクションのロールバックなど)。時には実行順序を混同し、deferが宣言時に実行されると思い込むことがあります。

解決策:

Deferは特別なブロックで、現在のスコープ(通常は関数)の終わりまでコードの実行を遅延させます。すべてのdeferは、配置の逆順(LIFO)で実行されます。これにより、リソースのクリーンアップ、メモリの解放、またはトランザクションのロールバックを集中管理できます。

コード例:

func processFile() { let file = File("/tmp/data.txt") file.open() defer { file.close() print("ファイルを閉じました") } // ファイルでの作業 print("データを読み込んでいます…") }

主な特徴:

  • スコープからのいかなる出口でも常に実行され、エラーや早期のreturnでも同様です。
  • 複数のdeferは逆順で実行されます。
  • 関数だけでなく、任意のスコープで使用できます。

ひねりのある質問。

アプリがクラッシュする前にdefer内のコードは実行されますか?

いいえ、deferのコードはスコープからの正常な出口時にのみ実行されます。アプリが異常終了(例えば、致命的なエラー)の場合、deferは実行されません。

defer内でreturnを使用できますか?

いいえ、できません。Deferブロックでは値を返したりスコープを終了することはできず、命令のみが許可されます。

deferはdeferより前に宣言された変数を変更するために使用できますか?

はい、deferは実行時に現在のスタックの値をキャッチします。deferの前に宣言された値を変更することができ、スコープを出る際に保持されます。

コード例:

func example() -> Int { var result = 0 defer { result = 42 } return result // deferが実行され、結果は42 }

一般的なエラーとアンチパターン

  • 宣言後すぐにdeferが実行されると誤って期待すること。
  • 意味のないスコープ外でのdeferの使用。
  • defer内に重い処理を残すこと。

実際の例

ネガティブケース

ファイルが開かれますが、関数の最後で明示的にクローズされ、エラーや関数からの早期退出でファイルが開いたままになります。

利点:

  • 実装が簡単。

欠点:

  • エラー時にファイルが閉じない。
  • リソースのリーク。

ポジティブケース

ファイルを開いた直後にdeferを使用してファイルを閉じます。例外が発生したり関数から戻ったりしても、ファイルは必ず閉じられます。

利点:

  • 安全で、リークがない。
  • クリーンで予測可能なコード。

欠点:

  • defer内の可変リソースには注意が必要です。