【问题标题】:SwiftUI getting data out of coordinator into content viewSwiftUI 将数据从协调器中获取到内容视图中
【发布时间】:2026-01-31 04:10:01
【问题描述】:

我正在我的应用程序中构建一个 QR 码阅读器,到目前为止,我将它作为工作表打开并在检测到 qr/条形码时关闭。 应用程序的阅读器部分使用 UIKit,我有文件 QRCodeScan.swift,它是 UIViewControllerRepresentable,qr 扫描仪返回它在此文件中的协调器中找到的代码的值。 我似乎找不到任何方法将找到的代码从协调器中取出到原始视图中。

这是文件 QRCodeScan。

struct QRCodeScan: UIViewControllerRepresentable {

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> ScannerViewController {
        let vc = ScannerViewController()
        vc.delegate = context.coordinator
        return vc
    }

    func updateUIViewController(_ vc: ScannerViewController, context: Context) {
    }

    class Coordinator: NSObject, QRCodeScannerDelegate {
        @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

        func codeDidFind(_ foundCode: String) {
            print(foundCode)
            /*this is where the code comes to, need to return it from here */
            presentationMode.wrappedValue.dismiss()
        }

        var parent: QRCodeScan

        init(_ parent: QRCodeScan) {
            self.parent = parent
        }

    }
}

这是调用 qr 阅读器的 ContentView 的裁剪版本,这是我需要将找到的代码放回的地方

struct ContentView: View {

    @State var presentQRScanner = false

    var body: some View {
        NavigationView{
            Form{
                Section(header: Text("Info")){
                    Button("Scan Barcode"){
                        self.presentQRScanner = true
                    }
                        .sheet(isPresented: $presentQRScanner){QRCodeScan()}
                }

            }

            .navigationBarTitle(Text("New"), displayMode: .large)
            .navigationBarItems(trailing: Button("Save"){
                print("Button Pressed")
            })
        }
    }
}

我在这里遇到了一个完全的障碍,我找不到任何资源可以让我从协调器传回数据,也许我实施了一些错误,但我似乎无法适应任何其他解决方案适合

非常感谢任何帮助。

谢谢

【问题讨论】:

    标签: swift uikit swiftui


    【解决方案1】:

    您可能已经解决了这个问题,但解决方案是使用 ContentView 中的 @State 变量链接到 QRCodeScan Struct 和 Coordinator 类中的 @Binding 变量。

    看看这个答案:Accessing MKMapView elements as UIViewRepresentable in the main (ContentView) SwiftUI view

    这样的事情应该可以解决问题,但我建议阅读我链接的更详细的答案:

     struct QRCodeScan: UIViewControllerRepresentable {
    
        @Binding var code: String
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(code: $code)
    }
    
    func makeUIViewController(context: Context) -> ScannerViewController {
        let vc = ScannerViewController()
        vc.delegate = context.coordinator
        return vc
    }
    
    func updateUIViewController(_ vc: ScannerViewController, context: Context) {
    }
    
    class Coordinator: NSObject, QRCodeScannerDelegate {
        @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
       @Binding var code: String
    
       init(code: Binding<String>) {
       _code = code
       }
    
        func codeDidFind(_ foundCode: String) {
            print(foundCode)
            /*this is where the code comes to, need to return it from here */
            self.code = foundCode
            presentationMode.wrappedValue.dismiss()
        }
    
        var parent: QRCodeScan
    
        init(_ parent: QRCodeScan) {
            self.parent = parent
        }
    }
    }
    

    在您的 ContentView 中,创建@State var code,然后您可以调用 QRCodeScan(code: $code)。

    【讨论】:

      【解决方案2】:

      我已经在这个答案中为你回答了这个问题:SwiftUI go back programmatically from representable to View

      或者,您也可以通过在 QRCodeScan 上创建一个由代码调用的闭包来驱动演示者,然后让演示者解散。

      编辑:我已将我的建议插入到您的代码中,以向您展示谁拥有什么以及如何传递信息。

      struct QRCodeScan: UIViewControllerRepresentable {
      
          /// a closure called with the found code
          var onCodeScanned: (String) -> Void
      
          class Coordinator: NSObject, QRCodeScannerDelegate {
      
              func codeDidFind(_ foundCode: String) {
                  // call the parent's `onCodeScanned` closure here
                  parent.onCodeScanned(foundCode)
      
                  presentationMode.wrappedValue.dismiss()
              }
      
              var parent: QRCodeScan
      
              // init, makeViewController, etc.
          }
      }
      

      在演示者中:

      struct ContentView: View {
      
          @State var presentQRScanner = false
      
          var body: some View {
              NavigationView{
                  Form{
                      Section(header: Text("Info")){
                          Button("Scan Barcode"){
                              self.presentQRScanner = true
                          }
                          .sheet(isPresented: $presentQRScanner){
                              // when you create the VC representable, pass in your closure to handle found codes
                              QRCodeScan(onCodeScanned: {
                                  self.processFoundCode($0)
                              })
                          }
                      }
      
                  }
                  // .theRest()
              }
          }
      
          func processFoundCode(_ code: String) {
              // process it
      
              // dimiss sheet
              presentQRScanned = false
          }
      }
      

      换句话说,您的闭包会将数据沿链向上传递到您的ContentView

      【讨论】:

      • 是的,感谢您的帮助,我没有投反对票,我没有足够的 SO 点来显示我的投赞成票,但 defo 没有投反对票。您的解决方案实际上并不能帮助解决从协调器中获取“代码”的问题,无论我将“var onCodeScanned ...”行放在哪里,它要么无法从协调器访问,要么不是演示者可接受的实现