未処理のcompletionHandlerによるクラッシュを防止するガード追加

hotwired/hotwire-native-ios

未処理の completionHandler が呼び出されないと、WebKit が NSInternalInconsistencyException を送出しアプリ全体がクラッシュします。本 PR は、WKNavigationDelegateWKUIDelegate 系メソッドにガードを追加し、デリゲートが解放されても安全にハンドラを完了させることで安定性を向上させます。

背景

ColdBootVisitWKUIController の認証チャレンジや JavaScript アラート/確認パネルで、デリゲートが dealloc 後に WebKit がコールバックを発行すると、オプショナルチェーンが何もせずに抜け、必須の completionHandler が未呼び出しのまま例外が発生していました。実際のクラッシュレポートは completionHandler が呼び出されずに NSInternalInconsistencyException がスローされる形で報告され、ユーザーに致命的な影響を与えていました。

技術的な変更

全ての該当メソッドに guard let delegate を導入し、delegatenil の場合は安全なデフォルトを即座に返すロジックへ置き換えました。これにより、WebKit が要求する completionHandler が必ず呼び出され、例外が回避されます。

Navigator.session(_:didReceiveAuthenticationChallenge:completionHandler:)

変更前:

delegate?.didReceiveAuthenticationChallenge(challenge, completionHandler: completionHandler)

変更後:

guard let delegate else {
    completionHandler(.performDefaultHandling, nil)
    return
}
delegate.didReceiveAuthenticationChallenge(challenge, completionHandler: completionHandler)

Session.visit(_:didReceiveAuthenticationChallenge:completionHandler:)

変更前:

delegate?.session(self, didReceiveAuthenticationChallenge: challenge, completionHandler: completionHandler)

変更後:

guard let delegate else {
    completionHandler(.performDefaultHandling, nil)
    return
}
delegate.session(self, didReceiveAuthenticationChallenge: challenge, completionHandler: completionHandler)

ColdBootVisit.webView(_:didReceive:completionHandler:)

変更前:

delegate?.visit(self, didReceiveAuthenticationChallenge: challenge, completionHandler: completionHandler)

変更後:

guard let delegate else {
    completionHandler(.performDefaultHandling, nil)
    return
}
delegate.visit(self, didReceiveAuthenticationChallenge: challenge, completionHandler: completionHandler)

WKUIController.runJavaScriptAlertPanelWithMessage(_:completionHandler:)

変更前:

delegate?.present(alert, animated: true)

変更後:

guard let delegate else {
    completionHandler()
    return
}
let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .default) { _ in
    completionHandler()
})
delegate.present(alert, animated: true)

WKUIController.runJavaScriptConfirmPanelWithMessage(_:completionHandler:)

変更前:

delegate?.present(alert, animated: true)

変更後:

guard let delegate else {
    completionHandler(false)
    return
}
let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
    completionHandler(true)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
    completionHandler(false)
})
delegate.present(alert, animated: true)

設計判断

delegate がオプショナルである設計 を尊重しつつ、WebKit が要求する必須 completionHandler の呼び出し義務を明示的に保証する方針が採用されました。guard let delegate による早期リターンはコードの可読性を保ち、デフォルト動作(認証は .performDefaultHandling、確認は false、アラートは空呼び出し)を選択することで既存ロジックへの影響を最小限に抑えています。さらに、未発生の runJavaScriptAlertPanelWithMessage も同様に保護することで、同種の潜在的クラッシュを予防する余裕設計となっています。

まとめ

デリゲートが解放された後でも必須 completionHandler が確実に呼び出されるようガードを導入したことで、NSInternalInconsistencyException に起因するクラッシュを根本的に解消しました。最小限のコード追加で後方互換性と安全性を両立し、Hotwire‑Native‑iOS アプリ全体の安定性が向上します。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
3fbb4230

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文→背景→技術的変更→設計判断→まとめの5部構成が明確で、必須要素がすべて揃っている。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `言語:ファイルパス` の形式で正しく記述され、PRリンクも正しい形式で記載されている。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Swift と iOS のデリゲート概念を前提とした記述で、エンジニア向けの適切な技術レベルとなっている。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論・結論の流れを持ち、段落は1文で要点を示し、長すぎる段落や混在したトピックがない。空行で区切られている。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中の前後コードは提供されたDiffと完全に一致し、ファイルパスもDiffと合致している。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

delegate、guard let、completionHandler、.performDefaultHandling などの用語が正確に使用され、PRと矛盾しない。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

ガード追加により必須ハンドラが必ず呼び出される仕組みを正しく説明し、PRの意図と合致している。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

未呼び出しによる NSInternalInconsistencyException のクラッシュ説明や、ガード追加による安全化はPRで裏付けられている。推測や根拠のない記述はない。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #233 が正しく記載され、コード内の定数や戻り値もDiffと一致している。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの内容(未処理ハンドラによるクラッシュ防止)を適切に要約している。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に外部のバージョン情報やリリース日程等は含まれておらず、PR情報のみで完結している。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間に関する表現はなく、PRの記述と食い違いもない。