LoginSignup
2
4

More than 1 year has passed since last update.

SwiftUIのViewがなぜか更新されないときは `id(_:)` を付与すると解決するかもしれない

Posted at

以下のような、画像を取得するObservableObjectを @StateObject で保持している画像表示のViewを作成することがままあると思います。

import SwiftUI

struct ImageView: View {
    @StateObject var imageProvider = ImageProvider()
    let url: URL

    var body: some View {
        ZStack {
            if let image = imageProvider.image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
            }
        }
        .frame(height: 300)
        .onAppear {
            imageProvider.fetchImage(url: url)
        }
    }
}

class ImageProvider: ObservableObject {
    @Published var image: UIImage?

    func fetchImage(url: URL) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data, let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.image = image
                }
            }
        }.resume()
    }
}

画像を一度だけ取得する場合は問題なのですが、以下のように任意の契機で別の画像を取得したい場合に期待通りに画像が更新されません。

import SwiftUI

struct ContentView: View {
    @State var pictureNumber = 0

    var body: some View {
        ImageView(url: URL(string: "https://picsum.photos/id/\(pictureNumber)/500/500")!)

        Button {
            pictureNumber += 1
        } label: {
            Text("Change")
        }
    }
}

画像取得処理が確実に呼ばれるようにImageViewのイニシャライザー内に imageProvider.fetchImage(url: url) を置いても特に改善しません。

struct ImageView: View {
    @StateObject var imageProvider: ImageProvider
    let url: URL

    init(url: URL) {
        self.url = url
        let imageProvider = ImageProvider()
        _imageProvider = StateObject(wrappedValue: imageProvider)
        imageProvider.fetchImage(url: url)
    }
...

結局以下のようにImageViewに .id() を付与することで解決しました。
idが更新されると対象のViewの状態がリセットされるとのことです。

struct ContentView: View {
...
        ImageView(url: URL(string: "https://picsum.photos/id/\(pictureNumber)/500/500")!)
            .id(pictureNumber)
...

参考

環境

Xcode 14.1.0
Swift 5.7.1

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4