SwiftUI 超时警报警告然后超时

SwiftUI Timeout Alert Warning Then Timed Out

我设置了一个计时器来显示两个警报。第一个警报向用户显示一个警告,上面写着“嘿,你已经有一段时间没有活动了,你还在这里吗”,如果他们点击是,它就会重置计时器。如果他们不点击警报按钮,则在 x 时间后显示第二个警报,通知他们他们的会话已过期。他们点击“确定”,然后离开导航视图并返回主页。

一切正常,但是 XCode 抛出以下错误:

[Presentation] Attempt to present <SwiftUI.PlatformAlertController: 0x7fc2fa031800> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x7fc2e9f05530> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_24NavigationColumnModifier__: 0x7fc309f28e80>) which is already presenting <SwiftUI.PlatformAlertController: 0x7fc2ea842000>.

据我了解,这就是说,已经显示了一条警报,即使我要关闭它并显示您的其他警报,我也会对此进行投诉,这告诉我我'我做错了什么。我想确保我做的是正确的,这样我就不会在 XCode 的控制台中收到这个错误。

创建计时器后,我正在使用 onReceive 观看它:

.onReceive(timer) { time in
            if userTimeout == true {
                timer.upstream.connect().cancel()
            } else {
            caWarning()
            caTimeout()
            }
        }

两个函数真的很简单:

func caWarning() {
    if Date.now >= userActivity.addingTimeInterval(5*1) {
        userActivityAlert = true
    }
}

func caTimeout() {
    if Date.now >= userActivity.addingTimeInterval(10*1) {
        userActivityAlert = false
        userTimeout = true
    }
}

最后,我的警报 if 语句是:

if userActivityAlert == true {
            VStack {
                EmptyView()
            }
            .alert("Foo", isPresented: $userActivityAlert, actions: {
                Button("I'm Here") {
                    userActivity = Date.now
                }
            }, message: { Text("Are you still there?") }
        ) // End show alert
        } else if UserTimeout == true {
            VStack {
                EmptyView()
            }
            .alert("Foo", isPresented: $userTimeout, actions: {
                Button("OK") {
                    self.caRegExpired.navToHome = true
                }
            }, message: {
                    Text("Your session has expired.\nTap OK, to start over.")
            }) // End Alert
        } // End If

能想到的我都试过了。从 @Environment (\.dismiss) var dismiss 然后调用 dismiss()(关闭底层视图而不是警报),到浏览 Apple 的文档和旧的 UIKit 东西(没有帮助)。

我可以这样做(即两个单独的警报)或者能够在一段时间后将第一个警报修改为第二个警报(甚至可能显示倒计时,直到用户会话结束)已过期)。

老实说,我想知道这是否只是记录噪音,因为第一个警报消失了,而第二个警报完全正常显示。从字面上看,这一切都很好,但重要的是要解决错误,我想知道我是否做错了什么。

这是针对最新的 SwiftUI 5+,XCode 是针对 iOS 15+

@loremipsum 的 link 给出了答案:在停用第一个警报和显示第二个警报之间稍等片刻:

struct ContentView: View {
    
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    @State private var userActivityAlert = false
    @State private var userTimeout = false
    @State private var userActivity = Date.now
    
    var body: some View {
        
        VStack {
            Text("Hello, World!")
                .alert("Foo", isPresented: $userActivityAlert, actions: {
                    Button("I'm Here") {
                        userActivity = Date.now
                    }
                }, message: { Text("Are you still there?") }
                ) // End show alert
            
            Text("Hello, World!")
                .alert("Foo", isPresented: $userTimeout, actions: {
                    Button("OK") {
                        //                        self.caRegExpired.navToHome = true
                    }
                }, message: {
                    Text("Your session has expired.\nTap OK, to start over.")
                }) // End Alert
            
        }
        .onReceive(timer) { time in
            if userTimeout == true {
                timer.upstream.connect().cancel()
            } else {
                caWarning()
                caTimeout()
            }
        }
    }
    
    func caWarning() {
        if Date.now >= userActivity.addingTimeInterval(5*1) {
            userActivityAlert = true
        }
    }
    
    func caTimeout() {
        if Date.now >= userActivity.addingTimeInterval(10*1) {
            userActivityAlert = false
            
            //This delay leaves a little gap between alerts
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                userTimeout = true
            }
        }
    }
}