Q1:为什么onAppears被调用两次?
第二季度:或者,我可以在哪里拨打网络电话?
我在代码中的几个不同位置放置了onAppears,它们都被调用了两次。最终,我会尝试在显示下一个视图之前进行网络呼叫,因此,如果您知道无需使用onAppear即可进行此操作的方法,那么我无所不能。
我还尝试过在列表中放置和删除ForEach,但它没有任何改变。
Xcode 12 Beta 3->目标iO 14 CoreData已启用但尚未使用
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")
})
}
}
答案 0 :(得分:3)
我有同样的问题。
我所做的是:
struct ContentView: View {
@State var didAppear = false
@State var appearCount = 0
var body: some View {
Text("Appeared Count: \(appearrCount)"
.onAppear(perform: onLoad)
}
func onLoad() {
if didAppear = false {
appearCount += 1
//This is where I loaded my coreData information into normal arrays
}
didAppear = true
}
}
这通过确保onLoad()的if条件内部的内容仅运行一次来解决。
更新:Apple Developer论坛上的某人已提交了票证,Apple知道了此问题。我的解决方案是暂时的措施,直到Apple解决问题为止。
答案 1 :(得分:1)
我一直在使用这样的东西
import SwiftUI
struct OnFirstAppearModifier: ViewModifier {
let perform:() -> Void
@State private var firstTime: Bool = true
func body(content: Content) -> some View {
content
.onAppear{
if firstTime{
firstTime = false
self.perform()
}
}
}
}
extension View {
func onFirstAppear( perform: @escaping () -> Void ) -> some View {
return self.modifier(OnFirstAppearModifier(perform: perform))
}
}
我用它代替 .onAppear()
.onFirstAppear{
self.vm.fetchData()
}
答案 2 :(得分:0)
您可以创建一个bool变量来检查是否首次出现
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
})
}
}
答案 3 :(得分:0)
万一有人在我的船上,这是我现在解决的方法:
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")
}
}
}
}
答案 4 :(得分:0)
我们不必在.onAppear(perform)
上这样做
这可以在View的初始化上完成
答案 5 :(得分:0)
您可以为此错误创建首次出现的功能
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()
}
}
}
答案 6 :(得分:0)
我有这个应用程序:
@main
struct StoriesApp: App {
var body: some Scene {
WindowGroup {
TabView {
NavigationView {
StoriesView()
}
}
}
}
}
这是我的 StoriesView:
// ISSUE
struct StoriesView: View {
@State var items: [Int] = []
var body: some View {
List {
ForEach(items, id: \.self) { id in
StoryCellView(id: id)
}
}
.onAppear(perform: onAppear)
}
private func onAppear() {
///////////////////////////////////
// Gets called 2 times on app start <--------
///////////////////////////////////
}
}
我通过测量 onAppear() 调用之间的差异时间解决了这个问题。根据我的观察,onAppear() 的两次调用发生在 0.02 到 0.45 秒之间:
// SOLUTION
struct StoriesView: View {
@State var items: [Int] = []
@State private var didAppearTimeInterval: TimeInterval = 0
var body: some View {
List {
ForEach(items, id: \.self) { id in
StoryCellView(id: id)
}
}
.onAppear(perform: onAppear)
}
private func onAppear() {
if Date().timeIntervalSince1970 - didAppearTimeInterval > 0.5 {
///////////////////////////////////////
// Gets called only once in 0.5 seconds <-----------
///////////////////////////////////////
}
didAppearTimeInterval = Date().timeIntervalSince1970
}
}
答案 7 :(得分:0)
就我而言,我发现层次结构中的一些视图,.onAppear()
(和 .onDisappear()
)只被调用了一次,正如预期的那样。我用它来发布通知,我在需要对这些事件采取行动的视图中收听这些通知。这是一次严重的黑客攻击,我已经确认该错误已在 iOS 15b1 中修复,但 Apple 确实需要向后移植该修复程序。