It's my first question on stackoverflow. Please correct me if I wrong with formatting topic.
I get crash of application when try use long press (?haptic touch?) on real iPad. Also it's reproducible on Simulators iPad with Force Touch click on Magic Trackpad.
Which devices have this bug?
Every iPad since iOS 13.4 until the last iOS 13. Every Simulator iPad since iOS 13.4 until the last iOS 13.
I never saw this bug on iPhone.
My set up for testing: MacOS Catalina 10.15.6, xCode 11.7, Simulator iPad mini 2019 5-gen iOS 13.7, iPad 2018 6-gen iOS 13.7.
Upd 26.10.2020. Also, I try to use xCode 12.0.1 on MacOS Catalina 10.15.7, iPad 2018 6-gen iOS 13.7. I retested, looks like the bug still available on iOS 13.4-13.7, but is gone for iOS 14. Good decision for iOS 13 I didn't find.
Steps to reproduce the bug.
- I use SwiftUI view (
TestCrashIPAD
) with List, ForEach and dynamic sections (source code below). - Some static sections are predefined, some dynamic sections appear after fetching from server.
- IMPORTANT the bug reproducible only when first appear view! Don't go to another screen or minimize the app!
- Just open this view (
TestCrashIPAD
). - Wait until dynamic sections appers.
- As soon as the sections appear, try long-press on the cell with text "r1" or "r2" or ... (screenshot)
- Get crash (screenshot)
CRASH
I get crash on AppDelegate with:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
I investigated a little bit, and found: this bug reproducible since iOS 13.4. Also with iOS 13.4 there is a View Modifier onDrag (link). May be it's somehow connected, because in call stack I see:
UIDragInteractionLongPressDriver
UIGestureRecognizer
May be something wrong with dynamic sections array, because I see:
SwiftUI.Sections.rowIDs(forSectionAt: Swift.Int)
SwiftUI.ListCoreDataSource.rowIndex(at: Foundation.IndexPath)
Question
How to fix this issue? How to work around without crash in this case? Please, say any idea.
Source Code
Please have a look the source code:
import SwiftUI
struct TestCrashIPAD: View {
@State var sections = [TestSection]()
var body: some View {
List {
// predefined sections
Section(header: Text("Section predefined")) {
Text("1")
Text("2")
}
Section(header: Text("Section predefined")) {
ForEach(1..<7) {
Text("\($0)")
}
}
// dynamic content
ForEach(sections) { section in
Section(header: Text(section.title)) {
ForEach(section.rows) { row in
HStack {
Text(row.str)
Spacer()
}
}
}
}
}
.listStyle(GroupedListStyle())
.navigationBarTitle("iPad crash with long press")
.onAppear(perform: onAppearAction)
}
func onAppearAction() {
DispatchQueue.global().async {
// fetch some data from the server
sleep(3)
// show data in UI
DispatchQueue.main.async {
self.sections = [TestSection](TestSection.array)
}
}
}
}
struct TestSection: Identifiable {
let id = UUID()
let title: String
let rows: [TestRow]
static var array: [TestSection] {
var result = [TestSection]()
for idx in 0..<50 {
result.append(TestSection(title: "s\(idx)", rows: TestRow.array))
}
return result
}
}
struct TestRow: Identifiable {
let id = UUID()
let str: String
static var array: [TestRow] {
var result = [TestRow]()
for idx in 0..<Int.random(in: 3..<7) {
result.append(TestRow(str: "r\(idx)"))
}
return result
}
}