首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当代码没有递归时,Xcode崩溃报告怎么能说函数递归地调用自己呢?

当代码没有递归时,Xcode崩溃报告怎么能说函数递归地调用自己呢?
EN

Stack Overflow用户
提问于 2021-12-21 20:31:08
回答 1查看 474关注 0票数 -4

我们的应用程序崩溃了,这是堆栈跟踪的顶部:

代码语言:javascript
复制
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代码:

代码语言:javascript
复制
    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行是什么样子的。这种情况发生在这样的视图中:

代码语言:javascript
复制
@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,它永远不会打印这样的堆栈。当然可以,但是数组类需要这样的实现:

代码语言:javascript
复制
Array.remove(int index) {
   // perform logic
   // call Daniel Kaplan's code
}

当然,这是荒谬的。语言的藏书库不应该/不能直接引用我的。我假设SwiftUI是相同的,那么第0行到第4行有什么意义呢?

下面的评论说,

MyView.onPageChanged (每当页面索引更改时调用)调用viewModel.onPageChanged,该viewModel.onPageChanged操作页面数组的@已发布变量。在我看来是递归的。

其他人提出了这一理论,但如果是这样的话,我有两个后续问题:

  1. ,因为没有基本情况,它不是一直是一个无限循环,直到它因这个错误而崩溃吗?但是这个错误只发生了一次,我们无法重现它。
  2. 如果MyView.onPageChanged是它递归的地方,为什么它只在堆栈跟踪中出现一次?
EN

回答 1

Stack Overflow用户

发布于 2021-12-29 05:50:48

SwiftUI是一个反应性的世界,我们不应该考虑何时/if/如何调用修饰符(在大多数情况下),我们只需要在调用时作出反应,并做出正确的反应是我们的责任,因此为了确保代码安全,应该添加保护(无论如何,总是),就像

代码语言:javascript
复制
func onPageChanged(index: Int) {
    if !pagesData.isEmpty && index < pagesData.count {
        pagesData.remove(at: index)
    }
}

为什么会被称作两次--这是苹果的一个问题,而且很可能我们永远不会得到这样的问题的答案,即使他们有时解决了这个问题(相当安静),但你可以提交反馈。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70441293

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档