V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
netabare
V2EX  ›  iOS

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

  •  
  •   netabare · 2023-11-30 04:24:56 +08:00 · 1327 次点击
    这是一个创建于 396 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    大概是在实现「需要回到上一页」的时候发现出现的问题。相关的页面大概是:根页面 - 分页 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 。

    5 条回复    2023-12-12 01:50:10 +08:00
    alexcding
        1
    alexcding  
       2023-11-30 08:26:06 +08:00
    你用到 NavigationStack 跟 NavigationPath, 就不要和 NavigationLink(destination:混用)
    NavigationLink(destination: 是 iOS15 以及之前的, 用 NavigationLink(value), 或者直接 append path
    netabare
        2
    netabare  
    OP
       2023-12-01 23:26:17 +08:00   ❤️ 1
    @alexcding 感谢回复,稍微修复了一下,去掉`NavigationLink(destination:`后看起来可以通过`NavigationLink`进行正常导航了,也可以使用`presentationMode.wrapper.dismiss()`来去掉最后一页。

    不过关于`path.removeLast`还是有前面提到的问题,也就是如果不进行数据库交互的话,第一次 removeLast 不会有任何反应,按多几次程序会崩溃。虽说可以用`NavigationLink`或者`presentationMode`的`dismiss`函数来绕过就是了……
    alexcding
        3
    alexcding  
       2023-12-02 04:05:41 +08:00
    你传个版本到 github, 我看一下. 这边看 code 太累
    netabare
        4
    netabare  
    OP
       2023-12-10 01:10:55 +08:00   ❤️ 1
    @alexcding 应该是这个,链接 base64 了一下:
    aHR0cHM6Ly9naXRodWIuY29tL2tva29yby1heWEvYXNhZ2lyaS9ibG9iLzlhNmMyMGJjMzgxNGZiMjhhNDBmNmY0ZDI4OTI1YjdlNmNjOTE5Y2QvYXNhZ2lyaS9WaWV3cy9DcmVhdGVOZXdBcHBsaWNhdGlvblZpZXcuc3dpZnQjTDE0MQ==

    136-139 行的 dummy data 去掉的话就无法跳转+第二次点击时 crash 掉。
    alexcding
        5
    alexcding  
       2023-12-12 01:50:10 +08:00   ❤️ 1
    @netabare
    好像苹果是建议
    path.removeLast(path.count)

    其实输入新表格, 你用 sheet 比较好. 或者 fullscreencover 比较好.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1535 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 16:49 · PVG 00:49 · LAX 08:49 · JFK 11:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.