iOSアプリのソースコードで「嘘だろ・・・」と思ったもの

Written by じび on 12月 3rd, 2022

iOSアプリの仕事をやっていて、新規で作成するよりも既存のアプリの開発を引き継ぐことが多いのですが、ソースコードを見ていて思わず「嘘だろ・・・」と呟いてしまうようなものを紹介します。

この記事はEngineMaker界隈 Advent Calendar 2022 の3日目の記事です。

画面遷移をpushのみで行なっている

UINavigationControllerの画面遷移を全てpushで行なっていました。詳細画面に遷移する時だけではなく、元の画面に戻る場合もpushしていたのです。popしているところはありませんでした。

そのため画面を行ったり来たりすると次々に新しい画面のインスタンスが生成され、それらは消されでに画面スタックに積み重なっていき、やがてメモリ不足でアプリがクラッシュしてしまう、という状態でした。

一画面あたりのメモリ使用量が少なく(画面内の項目が少なかった)、また画面数も少なかったため、問題が発覚していませんでした。

【iOSアプリに詳しくない人に向けた解説】

特に詳細画面に遷移する場合など、UINavigationControllerクラスが使用されます。これは内部に表示された画面を保持するスタックを実装し、新しい画面に遷移する場合はpushで新しい画面をスタックに積み上げ、前の画面に戻る場合はpopで画面スタックから最後に表示された画面を取り外す、という方法を取ります。

このように今まで表示された画面のインスタンスが保持されていることにより、前の画面に戻る場合に画面インスタンの生成(とてもコストがかかる)をせずに素早く戻ることができます。

リスト表示画面をUIScreenViewで実装している

リスト画面が全てUIScrollViewで実装されていました。UITableViewは使用されていませんでした。

そのアプリにはいくつかのリスト画面があるのですが、ほとんど1ページ分くらいの項目しかなく、特に問題とされていませんでした。しかし、3ページ分くらいの項目があるリスト画面があり、そこのスクロールが異様に遅かったので調べてみたところ、全てUIScrollViewを使っていました。

【iOSアプリに詳しくない人に向けた解説】

リスト画面ではUITableViewを使用します。これは画面に見えている項目(以降セルと呼びます)の分だけインスタンスを生成し、スクロールさせた時に画面から見えなくなったセルのインスタンスを削除せずにストックしておき、新しく見えてきたセルとして再利用する仕組みになっています。

これにより、画面に見えている分のセルの分しかメモリを消費せず、また再利用することによってセルのインスタンスの生成(コストがかかる)を大幅に省くことができ、何万行もあるようなリストでもヌルヌルサクサク動かすことができます。

Webなんかだと何万行もある場合は100行ごとにページを分けたりしますが、iOSでは上記の仕組みによりその必要はないのです。

 

Leave a Comment