Mac_Play
Mac_Play

Reputation: 302

SwiftUI TabView PageTabViewStyle crashes without showing any error

I am trying to create an Image carousel using tabview and loading pictures from firebase. Without showing any error message or code tabview crashing. Please shed some light on what's going wrong here.

struct HomeView : View{
var body : View{
    NavigationView{
        VStack{
            ScrollView{
                CategoryView(homeViewModel: homeViewModel)
                PosterView(homeViewModel: homeViewModel)
            }
        }
        .navigationBarTitleDisplayMode(.inline)
        .navigationBarTitle("")
    }
}

}



struct PosterView : View {
@StateObject var homeViewModel : HomeViewModel = HomeViewModel()
@State var currentIndex: Int = 0
var timer = Timer.publish(every: 3, on: .main, in: .common)

func next(){
    withAnimation{
        currentIndex = currentIndex < homeViewModel.posterList.count ? currentIndex + 
        1 : 0
    }
}


var body: some View{
    Divider()
    GeometryReader{ proxy in
    VStack{
        TabView(selection: $currentIndex){
            ForEach(homeViewModel.posterList){ item in
                let imgURL = homeViewModel.trendingImgDictionary[item.id ?? ""]
                AnimatedImage(url: URL(string: imgURL ?? ""))
            }
        }.tabViewStyle(PageTabViewStyle())
        .padding()
        .frame(width: proxy.size.width, height: proxy.size.height)
        .onReceive(timer) { _ in
            next()
        }
        .onTapGesture {
            print("Tapped")
        }
        
    }
    }
}
}

ViewModel: It contains two methods to fetch data and pictures from Firebase. That's working fine and am getting proper data. The only issue is while displaying it tabview crashes without showing any error messages.

class HomeViewModel : ObservableObject {

  @Published var posterList : [TrendingBanner] = []
  @Published var trendingImgDictionary : [String : String] = [:]

  init() {
    self.fetchTrendingList()
  }
   func fetchTrendingList()  {
    self.posterList.removeAll()
    firestore.collection(Constants.COL_TRENDING).addSnapshotListener { snapshot, error in
        guard let documents = snapshot?.documents else{
            print("No Documents found")
            return
        }
        self.posterList = documents.compactMap({ (queryDocumentSnapshot) -> TrendingBanner? in
            return try? queryDocumentSnapshot.data(as:TrendingBanner.self )
        })
        print("Trending list \(self.posterList.count)")
        print(self.posterList.first?.id)
        let _ = self.posterList.map{ item in
            self.LoadTrendingImageFromFirebase(id: item.id ?? "")
        }
    }
}


 func LoadTrendingImageFromFirebase(id : String) {

    let storageRef = storageRef.reference().child("trending/\(id)/\(id).png")
    storageRef.downloadURL { (url, error) in
        if error != nil {
            print((error?.localizedDescription)!)
            return
        }
        self.trendingImgDictionary[id] = url!.absoluteString
        print("Trending img \(self.trendingImgDictionary)")
    }
}

Upvotes: 1

Views: 1058

Answers (2)

Yevhenii Orenchuk
Yevhenii Orenchuk

Reputation: 91

Had the same issue recently on devices running iOS 14.5..<15. Adding .id() modifier to the TabView solved it. Example:

TabView(selection: $currentIndex) {
    ForEach(homeViewModel.posterList) { item in
        content(for: item)
    }
}
.tabViewStyle(PageTabViewStyle())
.id(homeViewModel.posterList.count)

Upvotes: 0

Eugene Dudnyk
Eugene Dudnyk

Reputation: 6030

If you open SwiftUI module sources, you'll see the comment on top of TabView:

Tab views only support tab items of type Text, Image, or an image followed by text. Passing any other type of view results in a visible but empty tab item.

You're using AnimatedImage which is probably not intended to be supported by TabView.

Update I made a library that liberates the SwiftUI _PageView which can be used to build a nice tab bar. Check my story on that.

Upvotes: 1

Related Questions