Comment transmettre des données de viewController à swiftUI view?

Sep 23 2020

Je travaille sur une application qui utilise ARkit pour détecter les images. Lorsqu'une image dans le dossier d'actifs est détectée, l'application affiche une vue swiftUI au-dessus de l'image, et lorsqu'une image n'est plus suivie, la vue swiftUI disparaît. Jusqu'ici, tout fonctionne bien.

Dans la méthode viewdidload dans le fichier viewController, je télécharge et analyse un fichier csv à partir d'Internet. Cela fonctionne également.

Là où j'ai du mal, c'est de savoir comment passer les données analysées du fichier csv qui se trouve dans viewdidload à la vue swiftUI, afin que je puisse travailler avec ces données sur la vue swiftUI que je crée. Par exemple, je montrerai des données spécifiques en fonction de l'image détectée.

J'ai trouvé d'autres questions de stackoverflow où ils discutent de la façon de transmettre des données entre des contrôleurs de vue, mais pas entre un contrôleur de vue et une vue swiftUI.

Ci-dessous mon code.

Voici mon fichier 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
    }
    
   
}

et voici mon fichier de vue swiftUI

import SwiftUI

struct imageView: View {

    var imageName: String

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

Réponses

1 LouFranco Sep 24 2020 at 17:26

Vous voulez datosêtre passé au constructeur de la vue, mais le seul que datosvous avez dans votre code est une variable locale dans une fermeture.

Vous devez créer une nouvelle propriété dans le VC

var datos: [[String]]?

Ensuite, lorsque vous obtenez les données, enregistrez-les dans cette propriété

self.datos = ....

Ensuite, lorsque vous construisez la vue, passez self.datos