表示上はnilなのに、if letのチェックを通過している
事象
iOSアプリが特定のAPI環境でのみクラッシュが発生しました。該当のコードは以下です。
func sample(cookie: HTTPCookie?) {
//...省略
if let cookie = cookie {
let _ = HTTPCookie.requestHeaderFields(with: [cookie])//クラッシュ発生箇所
//...省略
}
//...省略
}
原因特定
アーカイブされたアプリでは100%クラッシュが再現しましたが、同じコードをXcodeでビルドしてインストールしたアプリではクラッシュが発生しませんでした。Debugできないため、調査と修正検証が非常に難しい状態でした。
試行錯誤の末、Xcodeのスキーム設定を調整することで、ようやくビルド版でもクラッシュを再現できるようになりました。
その後、if let cookie = cookie の前で print(cookie) を実行したところ、出力はnilと表示されました。しかし、if let のチェック自体は通過していたため、その後のコードが実行されてクラッシュに至りました。
試しに以下のようにcookie.nameやcookie.domainなどのプロパティをチェックすると、クラッシュを防げました。
if let cookie = cookie,
!cookie.name.isEmpty,
!cookie.domain.isEmpty,
!cookie.value.isEmpty {
let _ = HTTPCookie.requestHeaderFields(with: [cookie])
}
表示上はnilなのに、if letのチェックを通過している。この挙動から、問題のCookieは「nilではないが、中身が無効なHTTPCookie」であることが分かりました。
解決方法
if let cookie = cookie が期待通りに動作しなかった理由は、HTTPCookie() が内部的に nil なプロパティを持つ無効なCookieオブジェクトを生成していた可能性が高いためです。これは完全な nil ではないため if let のチェックを通過してしまいますが、ヘッダーフィールドに変換しようとした際にクラッシュを引き起こします。
以下のようにコードを修正することで、クラッシュが発生しなくなりました。
-
HTTPCookie() のような空のCookieインスタンスは使用しない
-
Cookieが無効な可能性がある場合、明示的に各プロパティをチェックする
-
HTTPCookie.requestHeaderFields(with:)を使う際は、事前に中身の妥当性を必ず確認すること
株式会社SKIYAKIのテックブログです。ファンクラブプラットフォームBitfanの開発・運用にまつわる知見や調べたことなどを発信します。主な技術スタックは Ruby on Rails / React / AWS / Swift / Kotlin などです。 recruit.skiyaki.com/
Discussion