How SwiftUI TabView Page handles big data

Viewed 383

I use TabView to browse albums because I need a paging function, but my album has thousands of pictures, and TabView is very slow to process. Is there any way to lazy loading so that TabView can handle thousands of data.

TabView(selection: $assetModel.identifier) {
    ForEach(0..<7000) { index in
        let asset = assetModel.assetArray[index]
        AssetPreviewItemView(asset: asset)
            .tag(asset.localIdentifier) 
    }
}
.tabViewStyle(.page(indexDisplayMode: .always))
.indexViewStyle(.page(backgroundDisplayMode: .always))
1 Answers

At the moment (Xcode13.2.1), TabView will init all of your 7000 AssetPreviewItemView each time you change your TabView's selection (everytime you swipe images), so that's why it's so laggy.

As I've found out so far (really hope that i was wrong) the only way you can swipe through page tab view without loading everything is using @State for index only (replace your $assetModel.identifier with something like $identifier from @State var identifier).

You can see TestTabPageViewCell init 7000 times for each swipe page in my test code:

import SwiftUI

struct TestTabPageView: View {
    @StateObject private var viewModel = TestTabPageViewModel()
    
    var body: some View {
        VStack {
            TabView(selection: $viewModel.index) {
                ForEach((0..<7000), id: \.self) { i in
                    TestTabPageViewCell(content: "\(i)").tag(i)
                }
            }
            .tabViewStyle(.page(indexDisplayMode: .always))
        }
    }
}

class TestTabPageViewModel: ObservableObject {
    @Published var index = 0
}

struct TestTabPageViewCell: View {
    var content: String
    init(content: String) {
        self.content = content
        print("init \(content)")
    }
    var body: some View {
        Text(content)
    }
}

to get rid of 7000 inits, you have to keep index as private use

struct TestTabPageView: View {
    @State var index = 0
    
    var body: some View {
        VStack {
            TabView(selection: $index) {
                ForEach((0..<7000), id: \.self) { i in
                    TestTabPageViewCell(content: "\(i)").tag(i)
                }
            }
            .tabViewStyle(.page(indexDisplayMode: .always))
        }
    }
}
Related