🌞

iOSアプリで表示する画像の表示速度を高速化させる方法

2023/06/24に公開

目的

iOSアプリで表示する画像の表示速度を高速化する方法をまとめて、ユーザー体験を向上させる。

前提

iOSアプリの概要

ファッションアイテムの検索アプリを個人で開発しています。ファッションアイテムは各ファッションブランドのECサイトからクローラーで収集しています。アプリは以下のように検索結果の一覧画面から詳細画面へ遷移します。

一覧画面 詳細画面

システム構成

ファッションアイテムは、iOSからLightsail上で構築されたFastAPIアプリケーションのバックエンドシステムから取得されます。アイテムの画像はファッションブランドから収集したファイルサイズの大きい高画質の画像のURLhttps://example.img.jp/111/hoge/xxxx.jpgAsyncImageで直接読み込んで表示しています。

課題

前述の通り、ファイルサイズの大きい高画質の画像のURLから画像を収集しているため、このアプリには画像の読み込みが遅い場合があり、ユーザー体験が悪いという課題があります。

一覧画面 詳細画面

画像の表示速度を向上させる方法

APPENDIXにある資料とChatGPTをもとに調べたところ、以下の方法で画像の表示速度を向上させることができるようです。

  1. 画像の最適化: 画像を最適化して、ファイルサイズを小さくすることができます。 これにより、画像がダウンロードされる速度が向上し、表示速度が改善されます。画像ファイルのサイズを減らすために、画質を下げることができますが、画質が低下することを避けるため、可能な限り圧縮を使用することが重要です。
    • たとえば、zozotownでもファイルサイズが小さい荒い画像とファイルサイズが大きい高画質の画像があり、それぞれ一覧画面で表示/詳細画面で表示しています。
  2. キャッシュの活用: 画像のキャッシュを活用することで、二度目以降の画像表示が高速化されます。画像を一度ダウンロードした後、次にその画像を表示する必要が生じた場合、キャッシュから画像を読み込むことができます。これにより、ダウンロードにかかる時間が削減され、表示速度が向上します。
  3. 画像プリロード: 画像プリロードを使用することで、アプリの初期起動時に必要な画像をダウンロードすることができます。このため、ユーザーが画像を表示する必要が生じた場合、画像をすぐに表示することができます。これにより、表示速度が向上します。
  4. ネットワーク接続の最適化: ネットワーク接続を最適化することで、画像のダウンロード速度が向上し、表示速度が改善されます。たとえば、HTTP/2を使用して複数のファイルを同時にダウンロードすることができます。また、CDNを使用して、ユーザーに近いサーバーから画像をダウンロードすることもできます。

一方、クローラーを改修してファイルサイズが小さい荒い画像を収集するように改修する方法もありますが、どのサイトからも収集できるか怪しいのと一般的な方法である上記の方法で解決しようと思います。そのため、システムを以下のように改修します。

  • CloudFront+S3を構築
    • 画像の最適化: Lightsail上で画像URLから画像をダウンロードし、ファイルサイズが小さい画像とそのままのサイズの画像をS3にアップロードします。
    • ネットワーク接続の最適化: CDNであるCloudFrontを構築し、ユーザーに近いサーバーから画像を表示します。
  • iOSの改修:
    • キャッシュの活用: 一覧画面で表示する画像をキャッシュすることで画面遷移した後でも画像を再表示する際の表示速度が向上します。
    • 画像プリロード: 一覧画面でスクロールする際に画像を先読みすることでユーザーにすぐに画像を表示します。
    • ファイルサイズの小さい画像を先に表示: 表示速度の向上ではなくユーザー体験向上のための改修ですが、詳細画面に遷移した際にファイルサイズの小さい荒い画像を先に表示し、裏側でファイルサイズの大きい高画質の画像をダウンロードします。

CloudFront+S3の構築

以下の手順をもとにCloudFront+S3を構築します。

https://zenn.dev/taiyou/articles/41045fd9edcbfd

BEの改修

BE側では、以下の改修を行いました。

  • 画像をリサイズし、サムネイル画像を生成
  • サムネイル画像をS3にアップロード

iOSの改修

iOSは、以下の改修を行いました。

商品詳細画面

// CachedAsyncImage : 画像をキャッシュ
CachedAsyncImage(url: URL(string: 通常サイズの商品画像URL)) { image in
    // 通常サイズの商品画像を表示
} placeholder: {
    CachedAsyncImage(url: URL(string: サムネイル商品画像URL)) { thumbnail in
        // サムネイル画像を表示
    } placeholder: {
        ProgressView()
    }
}

商品一覧画面

商品一覧画面では2~3カラムで商品画像を表示するため、通常サイズの商品画像を表示する必要がありません。そのため、サムネイル画像を表示するようにしました。

CachedAsyncImage(url: URL(string: サムネイル商品画像URL)) { image in
    // サムネイル画像を表示
} placeholder: {
    ProgressView()
}

APPENDIX

Discussion