疑似发现了 Swift 的 NavigationStack 和 NavigationPath 的 bug?

161 天前
 netabare

(还是说我用的方法不对劲)

大概是在实现「需要回到上一页」的时候发现出现的问题。相关的页面大概是:根页面 - 分页 1 - 分页 2 这样的路径。先是在分页 2 里面实现提交数据后返回根页面,试了好几次都似乎没什么问题。回退就寄了。

NavigationLink 和 Button 里 removeLast 掉 path 都试过了。NavigationLink 可以回到根页面但下一次访问分页 1 的时候会大概率闪回根页面,运气好进入分页后再访问分页 2 一定会被闪回去。Button 的话,会出现第一次按下去无反应,第二次按下去的时候 crash 的情况。猜测此时的 path 为空。

不过有趣的地方在于如果 Button 按下的交互逻辑里包含一个数据增删的操作(也就是在 modelContext 里面添加或者删掉随便什么东西),removeLast 也是可以正常运行的。这时候就可以从分页 2 返回到根页面,然后再进入也不会出现奇怪的问题或者被闪回去。但总感觉有点面向 Bug 开发了。

感觉是很奇怪的现象,这几天把 stackoverflow 翻了个底朝天也没找到相关的描述。不知道跟这个相关的原理或者 issue 是什么,尤其是为啥随便加个 dummy data 反而看起来又能跑了呢。

以下为相关的按钮的写法,去掉了不相关的代码:

根页面里:

ToolbarItem {
    NavigationLink(destination: SubPage1(pathManager: $pathManager)
        .navigationBarBackButtonHidden(true),
        label: {
            Label("Add Item", systemImage: "square.and.pencil")
        })
    }

分页 1 里面再进一步的按钮:

Button {
    let generated = SomeModel(...)
    generated.someRelationship = ...

    pathManager.path.append(generated)
    
} label: {
    Label("Save", systemImage: "paperplane.fill")
}
.navigationDestination(for: SomeModel.self) { x in
    SubPage2(pathManager: $pathManager, data: x)
    .navigationBarBackButtonHidden(true)
}
.disabled(!incomplete)

分页 2 里面回根页面的按钮:

这个可以正常使用。

Button {            

    modelContext.insert(data)

    let data2 = AnotherModel()

    modelContext.insert(data2)
    
    data2.someRelationship = ...
    
    pathManager.path.removeLast()
                
} label: {
    Label("Save", systemImage: "paperplane.fill")
}

这个就寄了。

Button {
    pathManager.path.removeLast()
    // 或者 removeLast(path.count),当然这种情况下就永远按不动
} label: {
    Label("Discard", systemImage: "minus")
}

版本:Xcode 15.0.1 ,虚拟机是 17.0.1 的 iPhone 15 Pro ,本机是 Sonoma 14.1.1 。

1050 次点击
所在节点    iOS
5 条回复
alexcding
161 天前
你用到 NavigationStack 跟 NavigationPath, 就不要和 NavigationLink(destination:混用)
NavigationLink(destination: 是 iOS15 以及之前的, 用 NavigationLink(value), 或者直接 append path
netabare
160 天前
@alexcding 感谢回复,稍微修复了一下,去掉`NavigationLink(destination:`后看起来可以通过`NavigationLink`进行正常导航了,也可以使用`presentationMode.wrapper.dismiss()`来去掉最后一页。

不过关于`path.removeLast`还是有前面提到的问题,也就是如果不进行数据库交互的话,第一次 removeLast 不会有任何反应,按多几次程序会崩溃。虽说可以用`NavigationLink`或者`presentationMode`的`dismiss`函数来绕过就是了……
alexcding
159 天前
你传个版本到 github, 我看一下. 这边看 code 太累
netabare
151 天前
@alexcding 应该是这个,链接 base64 了一下:
aHR0cHM6Ly9naXRodWIuY29tL2tva29yby1heWEvYXNhZ2lyaS9ibG9iLzlhNmMyMGJjMzgxNGZiMjhhNDBmNmY0ZDI4OTI1YjdlNmNjOTE5Y2QvYXNhZ2lyaS9WaWV3cy9DcmVhdGVOZXdBcHBsaWNhdGlvblZpZXcuc3dpZnQjTDE0MQ==

136-139 行的 dummy data 去掉的话就无法跳转+第二次点击时 crash 掉。
alexcding
149 天前
@netabare
好像苹果是建议
path.removeLast(path.count)

其实输入新表格, 你用 sheet 比较好. 或者 fullscreencover 比较好.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/996395

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX