如何将数据从 viewController 传递到 swiftUI 视图?
How do I pass data from viewController to swiftUI view?
我正在开发一款使用 ARkit 检测图像的应用。当检测到资产文件夹中的图像时,应用程序会在图像顶部显示一个 swiftUI 视图,当不再跟踪图像时,swiftUI 视图就会消失。到这里为止一切正常。
在 viewController 文件的 viewdidload 方法中,我正在从互联网上下载并解析一个 csv 文件。这也有效。
我苦苦思索的是如何将从 viewdidload 中的 csv 文件解析的数据传递到 swiftUI 视图,以便我可以在我创建的 swiftUI 视图上处理这些数据。例如,我将根据检测到的图像显示特定数据。
我发现了其他 Whosebug 问题,他们讨论了如何在 viewcontroller 之间传递数据,而不是在 viewcontroller 和 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)")
}
}
}
您希望将 datos
传递给视图的构造函数,但代码中唯一的 datos
是闭包中的局部变量。
您需要在 VC
中创建一个新的 属性
var datos: [[String]]?
然后,拿到数据后,保存在这个属性
self.datos = ....
然后,在构造View的时候,通过self.datos
我正在开发一款使用 ARkit 检测图像的应用。当检测到资产文件夹中的图像时,应用程序会在图像顶部显示一个 swiftUI 视图,当不再跟踪图像时,swiftUI 视图就会消失。到这里为止一切正常。
在 viewController 文件的 viewdidload 方法中,我正在从互联网上下载并解析一个 csv 文件。这也有效。
我苦苦思索的是如何将从 viewdidload 中的 csv 文件解析的数据传递到 swiftUI 视图,以便我可以在我创建的 swiftUI 视图上处理这些数据。例如,我将根据检测到的图像显示特定数据。
我发现了其他 Whosebug 问题,他们讨论了如何在 viewcontroller 之间传递数据,而不是在 viewcontroller 和 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)")
}
}
}
您希望将 datos
传递给视图的构造函数,但代码中唯一的 datos
是闭包中的局部变量。
您需要在 VC
中创建一个新的 属性var datos: [[String]]?
然后,拿到数据后,保存在这个属性
self.datos = ....
然后,在构造View的时候,通过self.datos