SwiftUI - Image flickering when View reloaded on Socket Data change

646 Views Asked by At

As i am moving from UIKit to SwiftUI, i am facing this weird issue where my Images are flickering whenever the List is reloaded in SwiftUI.

Below is the code of my SpotView (child view)

struct SpotView: View, Equatable {
    
    static func == (lhs: SpotView, rhs: SpotView) -> Bool {
        lhs.spotModel == rhs.spotModel
    }

    var spotModel : CoinPairMarketModel
    
    
    var body: some View {
     
        HStack() { 
            ZStack {
                WebImage(url: spotModel.quote_icon_url)
//                    .placeholder(Image("Bitcoin"))
                    .resizable()
                    .interpolation(.none) // disable interpolation
                    .aspectRatio(contentMode: .fit)
                    .background(SwiftUI.Color(uiColor: UIColor.getAppWhite()))
                    .clipShape(Circle())
                    .shadow(color: SwiftUI.Color(UIColor.getAppBlueShadowColor()), radius: 8, x: 0, y: 2)
                    .frame(width: 30, height: 30)
                    .padding(EdgeInsets(top: 0, leading: 15, bottom: -15, trailing: 0))
                    .refreshable {
                        // Perform any necessary actions or reload data here
                    }
                    .id(UUID())

And here is how its being called from the parent view

struct SpotMarketView: View {
    
    @ObservedObject var viewModel = SpotViewModel()
    
    let socketPublisher = NotificationCenter.default
        .publisher(for: .marketSocketUpdated)
    
    let searchPublisher = NotificationCenter.default.publisher(for: .marketSearchChanged)
  
    var body: some View {

                ScrollView {
                    LazyVStack(spacing:0) {
                        ForEach(viewModel.arrFilterCoinPair ?? [], id: \.self) { element in
                            Button {
                                viewModel.moveToTradeScreen(data: element)
                            } label: {
                                SpotView(spotModel: element, favoriteBtnAction: {
                                    viewModel.addRemoveFavorite(coinPair: element) {
                                    }
                                }).equatable()
                                    .id(UUID())
                            }
                            Rectangle().frame(height: 0.5)
                                .foregroundColor(SwiftUI.Color(UIColor.getAppSeperatorColor()))
                                .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))
                            
                        }.id(UUID())
                        
                    }
                }.background(SwiftUI.Color(UIColor.getAppWhite()))

What i understand is because ViewModel is an ObservedObject, its recreating the view again and again which is causing the image to flicker.

Here is the video to understand better

Is there any way to solve this?

I have searched the stackoverflow but unable to find any help.

Thanks for you support.

1

There are 1 best solutions below

0
On

After trying multiple things, like switching from SDWebImage to AsyncImage and trying all possibilities. Finally i was able to fix it by switching to Kingfisher library

Kingfisher library has a .loadDiskFileSynchronously() that helped in stopping flickering.

This is what i did

     KFImage(spotModel.quote_icon_url)
                .loadDiskFileSynchronously()
                .cacheMemoryOnly()
                .fade(duration: 0.25)
                .resizable()
                .interpolation(.none) // disable interpolation
                .aspectRatio(contentMode: .fit)
                .background(SwiftUI.Color(uiColor: UIColor.getAppWhite()))
                .clipShape(Circle())
                .shadow(color: SwiftUI.Color(UIColor.getAppBlueShadowColor()), radius: 8, x: 0, y: 2)
                .frame(width: 30, height: 30)
                .padding(EdgeInsets(top: 0, leading: 15, bottom: -15, trailing: 0))
                .refreshable {
                    // Perform any necessary actions or reload data here
                }
                .id(UUID())