我们的应用程序崩溃了,这是堆栈跟踪的顶部:
Thread 0 name:
Thread 0 Crashed:
0 MyApp 0x00000001029ddb44 Swift runtime failure: Index out of range + 0 (MyViewModel.swift:0)
1 MyApp 0x00000001029ddb44 remove + 20 (MyViewModel.swift:202)
2 MyApp 0x00000001029ddb44 MyViewModel.onPageChanged(index:) + 656
3 MyApp 0x00000001029ddb38 remove + 8 (MyViewModel.swift:0)
4 MyApp 0x00000001029ddb38 MyViewModel.onPageChanged(index:) + 644 (MyViewModel.swift:202)
5 MyApp 0x00000001029d9064 closure #3 in MyView.body.getter + 132 (MyView.swift:45)
6 MyApp 0x0000000102be07f4 partial apply for thunk for @escaping @callee_guaranteed (@unowned Int) -> () + 24 (<compiler-generated>:0)
7 MyApp 0x0000000102be4a60 thunk for @escaping @callee_guaranteed (@in_guaranteed Int) -> (@out ()) + 32 (<compiler-generated>:0)
8 MyApp 0x0000000102be0740 thunk for @escaping @callee_guaranteed (@unowned Int) -> () + 24 (<compiler-generated>:0)
9 MyApp 0x0000000102be9f68 partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Int) -> (@out ()) + 32 (<compiler-generated>:0)
10 MyApp 0x0000000102bf20e8 partial apply for closure #3 in Pager.PagerContent.body.getter + 60 (PagerContent.swift:208)
11 MyApp 0x0000000102bd6f24 partial apply for closure #1 in OnAnimationCompletedModifier.notifyCompletionIfFinished() + 60 (OnAnimationCompletedModifier.swift:33)
12 MyApp 0x0000000102bd6ba4 thunk for @escaping @callee_guaranteed () -> () + 20 (<compiler-generated>:0)
13 libdispatch.dylib 0x0000000180dc5924 _dispatch_call_block_and_release + 32 (init.c:1517)
14 libdispatch.dylib 0x0000000180dc7670 _dispatch_client_callout + 20 (object.m:560)
15 libdispatch.dylib 0x0000000180dd5b70 _dispatch_main_queue_callback_4CF + 944 (inline_internal.h:2601)
16 CoreFoundation 0x000000018110dd84 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 (CFRunLoop.c:1795)
17 CoreFoundation 0x00000001810c7f5c __CFRunLoopRun + 2540 (CFRunLoop.c:3144)
18 CoreFoundation 0x00000001810db468 CFRunLoopRunSpecific + 600 (CFRunLoop.c:3268)
19 GraphicsServices 0x000000019cc6738c GSEventRunModal + 164 (GSEvent.c:2200)
20 UIKitCore 0x0000000183a7d088 -[UIApplication _run] + 1100 (UIApplication.m:3493)
21 UIKitCore 0x00000001837fb958 UIApplicationMain + 2092 (UIApplication.m:5046)
22 SwiftUI 0x0000000188d947a4 closure #1 in KitRendererCommon(_:) + 164 (UIKitApp.swift:35)
23 SwiftUI 0x0000000188cc3928 runApp<A>(_:) + 252 (<compiler-generated>:0)
24 SwiftUI 0x0000000188ca50c0 static App.main() + 128 (App.swift:114)
25 MyApp 0x0000000102969734 $main + 52 (<compiler-generated>:6)
26 MyApp 0x0000000102969734 main + 64 (MyOtherView.swift:0)
27 dyld 0x00000001033f5aa4 start + 520 (dyldMain.cpp:879)这是一个超出范围的索引异常。
以下是MyViewModel代码:
private var shouldPrepareData = true
...
@Published var pagesData = [SomeClass]() {
didSet {
if shouldPrepareData {
shouldPrepareData = false
... // this does NOT call onPageChanged anywhere
}
}
}
...
func onPageChanged(index: Int) {
...
pagesData.remove(at: 0) // crashes here!
...
}当数组为空时,删除第一个元素会导致异常。防止这种情况是微不足道的,我对如何修复它不感兴趣,至少这一行代码不感兴趣。
我关心的是:这个堆栈跟踪(特别是第0行到第4行)有什么意义?如果当数组有一个元素时pagesData.remove(at: 0)被调用了两次,那么这个崩溃就会发生,而第0到第4行看起来肯定是这样的。但是代码中没有从第3行到第2行的内容,尽管堆栈跟踪显示了什么,array.remove()显然没有调用MyViewModel.onPageChanged(),那么我该如何理解呢?
这发生在线程0/main上,顺便说一句。其他人问第5行是什么样子的。这种情况发生在这样的视图中:
@StateObject var myViewModel = MyViewModel();
...
.onPageChanged { index in // <--- this is defined by a library
myViewModel.onPageChanged(index: index) // #5
// log event
}在我们的代码中没有其他地方调用myViewModel.onPageChanged。
外部onPageChanged (即事件处理程序)来自这个库:https://github.com/fermoya/SwiftUIPager
显然,我误解了关于快速堆栈跟踪的一些基本概念,但我不知道它是什么。我更熟悉JavaScript和Java,它永远不会打印这样的堆栈。当然可以,但是数组类需要这样的实现:
Array.remove(int index) {
// perform logic
// call Daniel Kaplan's code
}当然,这是荒谬的。语言的藏书库不应该/不能直接引用我的。我假设SwiftUI是相同的,那么第0行到第4行有什么意义呢?
下面的评论说,
MyView.
onPageChanged(每当页面索引更改时调用)调用viewModel.onPageChanged,该viewModel.onPageChanged操作页面数组的@已发布变量。在我看来是递归的。
其他人提出了这一理论,但如果是这样的话,我有两个后续问题:
MyView.onPageChanged是它递归的地方,为什么它只在堆栈跟踪中出现一次?发布于 2021-12-29 05:50:48
SwiftUI是一个反应性的世界,我们不应该考虑何时/if/如何调用修饰符(在大多数情况下),我们只需要在调用时作出反应,并做出正确的反应是我们的责任,因此为了确保代码安全,应该添加保护(无论如何,总是),就像
func onPageChanged(index: Int) {
if !pagesData.isEmpty && index < pagesData.count {
pagesData.remove(at: index)
}
}为什么会被称作两次--这是苹果的一个问题,而且很可能我们永远不会得到这样的问题的答案,即使他们有时解决了这个问题(相当安静),但你可以提交反馈。
https://stackoverflow.com/questions/70441293
复制相似问题