ProgrammingSwift開発者

Swiftにおける 'defer' とは何ですか?どのように機能し、どのように使用され、非標準の使用シナリオにはどのようなものがありますか?

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

回答。

defer 演算子は、現在のスコープを終了するまでコードの実行を遅延させます。通常は関数からの戻り時に実行されます。リソースのクリーンアップ、ファイルの閉鎖、およびメモリの解放などに便利で、いわゆる自動的なクリーンアップです。

特長:

  • deferブロックは、宣言された逆順(LIFO)で実行されます。
  • 呼び出しは常に行われます — 通常の関数の終了時、またはエラーがスローされた時でもです。
  • クリーンアップコードの重複を避け、関数のクリーンなアーキテクチャを維持できます。

例:

func processFile() { let file = openFile() defer { closeFile(file) } // ファイルの操作 // throw や return が実行された場合でも file は閉じられます }

典型外の使用: 'finally' タイプの構文の部分的な模倣、ログ記録や実行時間の追跡のためのコードのグルーピングなどです。

ひねりのある質問。

アプリケーションが関数の実行中に終了した場合、defer は実行されますか?

— いいえ。defer は、スコープの正常終了時(return、throw または正常な退出)のみ実行されます。アプリケーションが強制終了(たとえば、SIGKILL信号やfatalErrorによる)した場合、deferブロックは実行されません。

例:

func foo() { defer { print("クリーンアップ") } fatalError("クラッシュ!") // defer は実行されません }

このトピックの微妙さから生じた実際のエラーの例。


物語

ソケットを扱う関数が、throwの場合に接続をクリーンアップしませんでした。データが残り、接続が解放されませんでした。deferを追加した後、すべてが正常に動作しました:リソースは常に閉じられていました。


物語

開発者は、グローバルステートの解放のためにdeferに頼ろうとしました。fatalErrorが発生した場合、リソースが解放されず、サービスがブロックされ、再起動が必要になりました。


物語

関数でいくつかのdeferを宣言し、宣言順で実行されると考えました。その結果、リソースが誤った順序で閉じられました(例えば、最初にファイルディスクリプタが閉じられ、その後それにアクセスしようとしました)。解決策:deferブロックのLIFO順序を忘れないことです。