iOSアプリの保守対応中、
メモリリークが原因でアプリがクラッシュする事象に遭遇しました。
クラッシュ箇所は一見すると単純な for 文の中。
しかし調査していくと、Swift / ARC の特性を理解していないとハマるポイントだったため、
備忘も兼ねてまとめます。
🚨 発生していた問題
アプリが メモリリーク → メモリ圧迫 → クラッシュ
クラッシュ箇所は for 文の中
処理内容は画像生成やデータ変換などの 重い処理
一定回数ループするとアプリが落ちる
一見すると「なぜここで?」と思う場所でした。
🔍 for / while ループ中はメモリが解放されない?
Swift(正確には ARC + Objective-C ランタイム)では、
for 文や while 文の処理は、ループを抜けるまでオブジェクトが解放されないという仕様があります。
つまり…
for item in items {
let image = createHeavyImage(item)
// image を使った処理
}
この場合、
createHeavyImage() 内で生成された一時オブジェクトが ループ終了まで溜まり続ける 可能性があります。
結果として:
- メモリ使用量が増え続ける
- 一定量を超えたタイミングで iOS によって強制終了(クラッシュ)
という流れになります。
💡 解決策:autoreleasepool {} を使う
この問題は、
for文の中を autoreleasepool {} で囲う ことで解決できます。
✅ 修正前(問題あり)
for item in items {
let image = createHeavyImage(item)
process(image)
}
✅ 修正後(改善)
for item in items {
autoreleasepool {
let image = createHeavyImage(item)
process(image)
}
}
🔑 ポイント
autoreleasepool {} のスコープが終わるたびに
autorelease オブジェクトが 即座に解放される
各ループごとにメモリがクリーンな状態に戻る
これだけで、
メモリ使用量の増加が抑えられ、クラッシュが解消しました。
🧠 なぜこれで解決するのか?
iOSアプリでは内部的に、
UIKit
CoreGraphics
Image I/O
Objective-C API
などが autorelease を使って一時オブジェクトを管理しています。
autoreleasepool {} は、
「このスコープ内で発生した autorelease オブジェクトを
スコープ終了時にまとめて解放する」
ための仕組みです。
Swiftだけを書いているつもりでも、
内部では Objective-C の autorelease が使われていることが多くあります。
🎯 こんなケースで特に有効
大量の画像生成・変換
PDF / ファイル処理
JSON を大量にデコード
バッチ処理
ループ内で UIKit / CoreGraphics を使う処理
📝 まとめ
for / while 文の中では メモリが溜まり続けることがある
重い処理をループ内で行うと メモリリークのような挙動になる
autoreleasepool {} で囲うだけで
ループごとにメモリ解放が行われる
大量処理をする Swift コードでは 知っているかどうかで安定性が大きく変わる
✨ 一言でまとめると
Swiftのfor文でのクラッシュは、
ロジックではなく「メモリ解放タイミング」が原因なことがある。