首页 > 解决方案 > SwiftUI - 在工作表上显示工作表时间歇性崩溃

问题描述

当我在已经在工作表中的视图上显示工作表时,我发生了不可预测的崩溃。我已经能够慢慢地剥离我的视图和自定义类型的一部分,直到我得到下面仍然显示崩溃的非常简单和通用的视图结构。

当我与 TextField 交互然后与显示子表的按钮之一交互时,就会发生崩溃。有时需要在按钮和文本字段之间点击很多才能触发崩溃,有时它会立即发生(如下面的 GIF 所示)。有时我根本无法让崩溃发生,但我的用户不断报告它。

在下面的 gif 图中,崩溃发生在按下底部按钮的那一刻。您可以看到按钮永远不会退出其“按下”状态,并且工作表永远不会出现。

Xcode 没有提供任何有关崩溃的有用信息(截图如下)。

我只在运行 13.4.1 和 Xcode 11.4.1 的 iPhone XR 上实现了它。我已经在 iPhone 6s 和几个模拟器上尝试过,但无法触发崩溃,但用户已经在几个设备上报告了它。

struct ContentView: View {

    @State var showingSheetOne: Bool = false

    var body: some View {
        Button(action: { self.showingSheetOne = true }) {
            Text("Show")
        }
        .sheet(isPresented: $showingSheetOne) {
            SheetOne(showingSheetOne: self.$showingSheetOne)
        }
    }
}

struct SheetOne: View {

    @Binding var showingSheetOne: Bool
    @State var text = ""

    var body: some View {
        VStack {
            SheetTwoButton()
            SheetTwoButton()
            SheetTwoButton()
            TextField("Text", text: self.$text)
        }
    }

}

struct SheetTwo: View {

    @Binding var showing: Bool

    var body: some View {
        Button(action: {
            self.showing = false
        }) {
            Text("Hide")
                .frame(width: 300, height: 100)
                .foregroundColor(.white)
                .background(Color.blue)
        }
    }

}

struct SheetTwoButton: View  {

    @State private var showSheetTwo: Bool = false

    var body: some View {
        Button(action: { self.showSheetTwo = true } ) {
            Image(systemName: "plus.circle.fill")
                .font(.headline)
        }.sheet(isPresented: self.$showSheetTwo) {
            SheetTwo(showing: self.$showSheetTwo)
        }
    }

}

崩溃屏幕录制 Xcode 崩溃 01 Xcode 崩溃 02 Xcode 崩溃 03 Xcode 崩溃 04

标签: iosswiftswiftui

解决方案


几周前我遇到了类似的问题。事实证明,当我在打开键盘的情况下展示新工作表时,它会导致崩溃。

我发现UIApplication.shared.endEditing()在显示第二张纸之前使用可以解决问题

更新

对于 iOS 14,我创建了一个扩展,因为上述功能不再可用

extension UIApplication {
    
    static func endEditing() {
        let resign = #selector(UIResponder.resignFirstResponder)
        UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
    }
    
}

用法类似UIApplication.endEditing()


推荐阅读