web-dev-qa-db-fra.com

SwiFui OnAppear est appelé deux fois

Q1: Pourquoi les coutumes sont-ils appelés deux fois?

Q2: Alternativement, où puis-je faire mon appel réseau?

J'ai placé des couches à quelques endroits différents dans mon code et ils sont tous appelés deux fois. En fin de compte, j'essaie de faire appel à un appel de réseau avant d'afficher la prochaine vue, donc si vous connaissez un moyen de le faire sans utiliser ONAPPAR, je suis toutes les oreilles.

J'ai également essayé de placer et de supprimer un forach dans mes listes et cela ne change rien.

Xcode 12 beta 3 -> cible iOS 14 Coredata activé mais pas encore utilisé

struct ChannelListView: View {

@EnvironmentObject var channelStore: ChannelStore
@State private var searchText = ""
@ObservedObject private var networking = Networking()

var body: some View {
    NavigationView {
        VStack {
            SearchBar(text: $searchText)
                .padding(.top, 20)
             
            List() {

                ForEach(channelStore.allChannels) { channel in
                    
                    NavigationLink(destination: VideoListView(channel: channel)
                                    .onAppear(perform: {
                        print("PREVIOUS VIEW ON APPEAR")
                    })) {
                        ChannelRowView(channel: channel)
                    }
                }
                .listStyle(GroupedListStyle())
            }
            .navigationTitle("Channels")
            }
        }
    }
}

struct VideoListView: View {

@EnvironmentObject var videoStore: VideoStore
@EnvironmentObject var channelStore: ChannelStore
@ObservedObject private var networking = Networking()

var channel: Channel

var body: some View {
    
    List(videoStore.allVideos) { video in
        VideoRowView(video: video)
    }
        .onAppear(perform: {
            print("LIST ON APPEAR")
        })
        .navigationTitle("Videos")
        .navigationBarItems(trailing: Button(action: {
            networking.getTopVideos(channelID: channel.channelId) { (videos) in
                var videoIdArray = [String]()
                videoStore.allVideos = videos
                
                for video in videoStore.allVideos {
                    videoIdArray.append(video.videoID)
                }
                
                for (index, var video) in videoStore.allVideos.enumerated() {
                    networking.getViewCount(videoID: videoIdArray[index]) { (viewCount) in
                        video.viewCount = viewCount
                        videoStore.allVideos[index] = video
                        
                        networking.setVideoThumbnail(video: video) { (image) in
                            video.thumbnailImage = image
                            videoStore.allVideos[index] = video
                        }
                    }
                }
            }
        }) {
            Text("Button")
        })
        .onAppear(perform: {
            print("BOTTOM ON APPEAR")
        }) 
    }
}
7
AvsBest

Vous pouvez créer la première fonction d'apparition pour ce bogue

extension View {

    /// Fix the SwiftUI bug for onAppear twice in subviews
    /// - Parameters:
    ///   - perform: perform the action when appear
    func onFirstAppear(perform: @escaping () -> Void) -> some View {
        let kAppearAction = "appear_action"
        let queue = OperationQueue.main
        let delayOperation = BlockOperation {
            Thread.sleep(forTimeInterval: 0.001)
        }
        let appearOperation = BlockOperation {
            perform()
        }
        appearOperation.name = kAppearAction
        appearOperation.addDependency(delayOperation)
        return onAppear {
            queue.addOperation(delayOperation)
            queue.addOperation(appearOperation)
        }
        .onDisappear {
            queue.operations
                .first { $0.name == kAppearAction }?
                .cancel()
        }
    }
}
1
Calvin Chang

Au cas où quelqu'un d'autre est dans mon bateau, voici comment je l'ai résolu pour l'instant:

struct ChannelListView: View {

@State private var searchText = ""
@State private var isNavLinkActive: Bool = false
@EnvironmentObject var channelStore: ChannelStore
@ObservedObject private var networking = Networking()

var body: some View {
    NavigationView {
        VStack {
            SearchBar(text: $searchText)
                .padding(.top, 20)
            List(channelStore.allChannels) { channel in
                ZStack {
                    NavigationLink(destination: VideoListView(channel: channel)) {
                        ChannelRowView(channel: channel)
                    }
                    HStack {
                        Spacer()
                        Button {
                            isNavLinkActive = true
                            
                            // Place action/network call here
                            
                        } label: {
                            Image(systemName: "arrow.right")
                        }
                        .foregroundColor(.gray)
                    }
                }
                .listStyle(GroupedListStyle())
            }
            .navigationTitle("Channels")
            }
        }
    }
}
0
AvsBest

vous pouvez créer une variable bool pour vérifier si elle apparaît d'abord

struct VideoListView: View {
  @State var firstAppear: Bool = true

  var body: some View {
    List {
      Text("")
    }
    .onAppear(perform: {
      if !self.firstAppear { return }
      print("BOTTOM ON APPEAR")
      self.firstAppear = false
    })
  }
}
0
vdotup

Nous n'avons pas à le faire sur .onAppear(perform) Cela peut être fait sur Incipité

0
Wasim