

Swiftについて以下の内容について困っております。

## 発生したこと

NavigationLinkで2回遷移できる以下のようなアプリを作成しました。  
[![ダメな例](https://i.stack.imgur.com/GMHtL.gif)](https://i.stack.imgur.com/GMHtL.gif)

上記の通り挙動としては

  1. `subsubへ`で`SubsubTestView`に遷移(`SubsubTestView`のViewModelは`SubTestView`で渡してます)
  2. リストのどれかを指定すると、`DetailView`に遷移
  3. 編集して`submit`を押すと強制的に`SubsubTestView(ListのView)`に戻される ← ★これが問題

ソースコードは以下です

  * TestApp.swift

[code]

    import SwiftUI
    
    @main
    struct TestApp: App {
        var body: some Scene {
            WindowGroup {
              ContentView().environmentObject(EnvObj())
            }
        }
    }
    
[/code]

  * ContentView.swift

[code]

    import SwiftUI
    
    class EnvObj: ObservableObject {
      @Published var users = [User(name: "a"), User(name: "b"), User(name: "c")]
    }
    
    struct User: Hashable, Identifiable, Equatable {
      var id = UUID()
      var name = ""
      
      static func == (lhs: User, rhs: User) -> Bool{
        return lhs.id == rhs.id
      }
    }
    
    struct ContentView: View {
      @EnvironmentObject var envObj: EnvObj
      
      var body: some View {
        NavigationView {
          VStack {
            NavigationLink("subsubへ", destination: SubsubTestView(vm: VM(envObj: envObj)))
          }
        }
      }
    }
    
    struct SubsubTestView: View {
      @EnvironmentObject var envObj: EnvObj
      @ObservedObject var vm: VM
      
      var body: some View {
        List {
          ForEach(self.vm.envObj.users) { user in
            NavigationLink(
              user.name,
              destination: DetailView(vm: self.vm.vmd),
              tag: user,
              selection: self.$vm.vmd.selectedUser
            )
            .onTapGesture {
              self.vm.vmd.selectedUser = user
            }
          }
        }
      }
    }
    
    class VM: ObservableObject {
      var envObj: EnvObj = .init()
      @Published var vmd: VMD = .init()
      
      init(envObj: EnvObj) {
        self.envObj = envObj
        self.vmd.envObj = envObj
      }
    }
    
    struct DetailView: View {
      @ObservedObject var vm: VMD
      
      var body: some View {
        VStack {
          TextField("名前", text: (self.$vm.selectedUser ?? User()).name)
          Text(self.vm.selectedUser?.name ?? User().name)
          Button("submit", action: self.vm.submit)
        }
      }
    }
    
    class VMD: ObservableObject {
      var envObj: EnvObj = .init()
      @Published var selectedUser: User?
      
      private(set) lazy var submit = {
        if let user = self.selectedUser {
          self.update(user: user)
        }
      }
      
      func update(user: User) {
        self.envObj.users = self.envObj.users.map {
          return $0 == user ? user : $0
        }
      }
    }
    
    func ??<T>(binding: Binding<T?>, fallback: T) -> Binding<T> {
      return Binding(get: {
        binding.wrappedValue ?? fallback
      }, set: {
        binding.wrappedValue = $0
      })
    }
    
[/code]

## お聞きしたいこと

  * 強制的に戻る現象の理由と解決方法を知りたいです。

## こちらで試したこと

  * 最初の`subsubへ`の行程をなくしてみたら、更新後の強制的な遷移は無くなりました。(EnvironmentObjectの設定のため一覧ページのVMが若干変わっています)

[code]

    class VM2: ObservableObject {
      @Published var envObj: EnvObj = .init()
      @Published var vmd: VMD = .init()
      var settingDone = false
      
      func setting(envObj: EnvObj) {
        if !settingDone {
          self.envObj = envObj
          self.vmd.envObj = envObj
          self.settingDone = true
        }
      }
    }
    
    struct EnvTestView: View {
      @EnvironmentObject var envObj: EnvObj
      @ObservedObject var vm: VM2 = .init()
      
      var body: some View {
        NavigationView {
          List {
            ForEach(self.vm.envObj.users, id: \.id) { user in
              NavigationLink(
                user.name,
                destination: DetailView(vm: self.vm.vmd),
                tag: user,
                selection: self.$vm.vmd.selectedUser
              )
              .onTapGesture {
                self.vm.vmd.selectedUser = user
              }
            }
          }
        }
        .onAppear(perform: {
          self.vm.setting(envObj: envObj)
        })
      }
    }
    
[/code]

長文申し訳ないです。よろしくお願いいたします。


CC BY-SA 4.0
2021-07-03T05:02:59.490
77933
2021-07-03T06:43:35.270
2021-07-03T06:43:35.270
24870
24870
question
swift ios swiftui
SwiftUI: NavigationLinkで遷移後の画面でデータを更新すると前に戻される