SwiftUI 将数据从协调器中获取到内容视图中

Posted

技术标签:

【中文标题】SwiftUI 将数据从协调器中获取到内容视图中【英文标题】:SwiftUI getting data out of coordinator into content view 【发布时间】:2019-10-17 17:24:22 【问题描述】:

我正在我的应用程序中构建一个 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")
            )
        
    

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

非常感谢任何帮助。

谢谢

【问题讨论】:

【参考方案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 ...”行放在哪里,它要么无法从协调器访问,要么不是演示者可接受的实现

以上是关于SwiftUI 将数据从协调器中获取到内容视图中的主要内容,如果未能解决你的问题,请参考以下文章

从公共 API 获取 JSON 以在 SwiftUI 的列表视图中呈现

将数据从 UIViewRepresentable 函数传递到 SwiftUI 视图

SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View

如何将数据从父模型类传递到 SwiftUI 中的子视图

是否可以在 SwiftUI 中提供服务并将数据推送到视图并更新 UI?

结合 SwiftUI 远程获取数据 - ObjectBinding 不更新视图