【问题标题】:How do I pass data from viewController to swiftUI view?如何将数据从 viewController 传递到 swiftUI 视图?
【发布时间】:2021-01-09 17:04:34
【问题描述】:

我正在开发一个使用 ARkit 检测图像的应用。当检测到资产文件夹中的图像时,应用程序会在图像顶部显示一个 swiftUI 视图,当不再跟踪图像时,该 swiftUI 视图会消失。到这里为止一切正常。

在 viewController 文件中的 viewdidload 方法中,我正在从 Internet 下载并解析一个 csv 文件。这也有效。

我正在努力的地方是弄清楚如何将从 viewdidload 中的 csv 文件解析的数据传递到 swiftUI 视图,以便我可以在我正在创建的 swiftUI 视图上处理这些数据。例如,我将根据检测到的图像显示特定数据。

我发现了其他 stackoverflow 问题,他们讨论了如何在视图控制器之间传递数据,而不是在视图控制器和 swiftUI 视图之间传递数据。

下面是我的代码。

这是我的 ViewController.swift 文件

import UIKit
import SceneKit
import ARKit
import SwiftUI

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!
    

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the view's delegate
        sceneView.delegate = self
        
        // load csv file from dropbox
        let url = URL(string: "https://www.dropbox.com/s/0d0cr5o9rfxzrva/test.csv?dl=1")!
        let task = URLSession.shared.downloadTask(with: url) { location, response, error in
            guard let location = location else { return }
            do {
                // get path to directory
                let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                print(documentDirectory.path)
                // giving name to file
                let name = (response as? HTTPURLResponse)?.suggestedFilename ?? location.lastPathComponent
                //create a destination url
                let destination = documentDirectory.appendingPathComponent(name)
                // check if file already exist
                if FileManager.default.fileExists(atPath: destination.path) {
                    //remove the file
                   try FileManager.default.removeItem(at: destination)
                }
                // move file from old to new url
                try FileManager.default.moveItem(at: location, to: destination)
                // reading the file
                let data = try String(contentsOf: destination, encoding: .utf8)
                
                //parsed csv
                let datos = self.csv(data: data)
                print(datos)
                
            } catch {
                print("ERROR", error)
            }
        }
        task.resume()
        
    }
    

    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // Create a session configuration
        let configuration = ARImageTrackingConfiguration()

        guard let trackingImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
        
            fatalError("Couldn't load tracking images")
            
            }
           
            configuration.trackingImages = trackingImages
            
        configuration.maximumNumberOfTrackedImages = 2
        
        // Run the view's session
        sceneView.session.run(configuration)
    }
        
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Pause the view's session
        sceneView.session.pause()
    }

    // MARK: - ARSCNViewDelegate
    

    // Override to create and configure nodes for anchors added to the view's session.
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        
        guard let imageAnchor = anchor as? ARImageAnchor else {return nil}
        
        
        let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width,
                         height: imageAnchor.referenceImage.physicalSize.height)
        
    
        let planeNode = SCNNode(geometry: plane)
        
        planeNode.eulerAngles.x = -.pi / 2
        
        
        if let imageName = imageAnchor.referenceImage.name {
            imageController(for: planeNode, imageName: imageName)
            
        }
    
        
        let node = SCNNode()
        node.addChildNode(planeNode)
        return node
            
        }

   


    func imageController(for node: SCNNode, imageName: String) {
    
    
        let imgView = UIHostingController(rootView: imageView(imageName: imageName))
    
    DispatchQueue.main.async {
        imgView.willMove(toParent: self)
        
        self.addChild(imgView)
        
        imgView.view.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
        
        self.view.addSubview(imgView.view)
        
        self.showImageView(hostingVC: imgView, on: node)
        
    }
    
    }

    

func showImageView(hostingVC: UIHostingController<imageView>, on node: SCNNode) {
        
        let material = SCNMaterial()
        
        hostingVC.view.isOpaque = false
        material.diffuse.contents = hostingVC.view
        node.geometry?.materials = [material]
        
        hostingVC.view.backgroundColor = UIColor.clear
        
    }

    
// parsing csv method
    func csv(data: String) -> [[String]] {
        var result: [[String]] = []
        let rows = data.components(separatedBy: "\n")
        for row in rows {
            let columns = row.components(separatedBy: ",")
            result.append(columns)
            
        }
        return result
    }
    
   
}

这是我的 swiftUI 视图文件

import SwiftUI

struct imageView: View {

    var imageName: String

    var body: some View {
        
        ZStack{
        Color.white
            Text("hello \(imageName)")
            
        }
            
        
    }
}

【问题讨论】:

  • 也许您可以尝试使用 NotificationCenter 或 Combine Publishers 来传递数据
  • 您已经使用imageName 在控制器之间传递数据。只需添加另一个您想要发送到您的imageView 类型的var,添加相同的var 并键入您的ViewController。当您下载 csv 时,不要使用 let davos 创建变量,而是设置您刚刚在控制器上添加的属性,然后将 var 发送到您的 imageView,就像发送 imageName 一样。
  • 感谢@clawesome。我是这么想的,因为我可以通过 imageName。但是,当我尝试对datos 执行相同操作时,我得到“使用未解析的标识符”。我显然错过了一些东西。你能在我的代码上显示吗?谢谢。
  • datos 是什么类类型?
  • 多维数组[[String]]

标签: ios swift swiftui viewcontroller arkit


【解决方案1】:

您希望将datos 传递给视图的构造函数,但您的代码中唯一的datos 是闭包中的局部变量。

你需要在VC中新建一个属性

var datos: [[String]]?

然后,当你得到数据时,将它保存在这个属性中

self.datos = ....

然后,当你构造视​​图时,传递self.datos

【讨论】:

  • 谢谢。那行得通。我也错过了将 datos 传递给 imageController 方法
猜你喜欢
  • 2021-03-05
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
相关资源
最近更新 更多