В моей раскадровке у меня есть 2 простых viewController. Представление, которое отображается при запуске приложения с простой компоновкой, содержащей кнопку. При нажатии на кнопку переходите, показывая второй viewController, в котором находится ARSCNView.
@IBOutlet weak var sceneView: ARSCNView!
В viewDidLoad я могу добавить 3D-объект, также есть touchBegin, чтобы показать дополнительный 3D-объект при нажатии на плоскость. Прекрасно работает.
Однако мой первый viewController должен инициировать добавление 3D-объекта на сцену при определенном делегате, который происходит в моем первом viewController. Первый viewController просто вызывает функцию на моем втором viewController для добавления 3D-объекта (та же функция, которую я использую для добавления 3D-объекта при нажатии на плоскость).
secondViewController.add3DObject()
Когда он вызывает add3DObject из моего первого viewController, sceneView равен нулю.
Когда я могу добавить 3D-объект, который запускается вторым viewController, почему я не могу запускать одно и то же с помощью другого viewController?
Первый viewController: (исключая весь код, не относящийся к проблеме)
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
var arSceneViewController = ARSceneViewController() //second viewController
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
// omitting some logic here....
// call a function in second view controller
arSceneViewController.addARItems(item: item)
}
}
второй viewController: (исключая весь код, не относящийся к проблеме)
class ARSceneViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet weak var sceneView: ARSCNView!
// this works
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let touchLocation = touch.location(in: sceneView)
let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
var arItem = ARItem()
arItem.itemDescription = "hello"
if let hitResult = results.first{
// calling this works from here
addARItems(item: arItem ,atLocation: hitResult)
}
}
}
// Called from first ViewController doesn't work
// Called from the same file work (from touchesBegin)
func addARItems(item: ARItem, atLocation location:ARHitTestResult? = nil){
// sceneView is nil!!!
guard let sView = sceneView else { return }
// omitted some insignificant code here ...
let cube = SCNBox(width:0.5, height: 0.1, length: 0.1, chamferRadius: 0.01)
let node = SCNNode()
node.position = SCNVector3(0, 0.1, -0.5)
node.geometry = cube
sceneView.scene.rootNode.addChildNode(node)
}
}
Добавлен пример кода выше. Надеюсь, это имеет смысл.
В контроллере первого представления var arSceneViewController = ARSceneViewController() //second viewController
Я думаю, здесь вы должны инициализировать контроллер второго представления из раскадровки?
Спасибо за ваше предложение... Я новичок в Swift. Не могли бы вы уточнить, как я буду это делать, пожалуйста?
Хорошо, я опубликую код в качестве своего ответа, вы можете попробовать и сообщить мне, работает ли он.
Как уже говорилось, я надеюсь, что этот код работает для вас.
При нажатии на кнопку переходите, показывая второй viewController, в котором находится ARSCNView. --> Таким образом, мы получим второй контроллер представления, переопределив функцию подготовки к переходу (пожалуйста, замените «ваш идентификатор перехода для второго контроллера представления» фактическим идентификатором, который вы установили в раскадровке).
А в делегате locationManager didUpdateHeading мы проверим, есть ли там второй вью-контроллер и тогда вызовем addARItems
var arSceneViewController: ARSceneViewController? //second viewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "your segue id for second view controller" {
arSceneViewController = segue.destination as? ARSceneViewController
}
}
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
// omitting some logic here....
// call a function in second view controller
if let arSceneVC = arSceneViewController {
arSceneVC.addARItems(item: item)
}
}
Большое вам спасибо за вашу помощь!! Это сработало. Требуется ли всегда готовиться к переходу? У меня это было только в раскадровке.
Рад, что это помогает вам. На самом деле это зависит от того, как вы настроите свою раскадровку. Если вы настроите переход для отправки на новый контроллер представления, вам придется переопределить этот метод, чтобы получить целевой контроллер представления. В противном случае, если вы активируете ручное нажатие/представление, вы инициируете второй контроллер представления из раскадровки и сохраняете ссылку на него для использования.
Не могли бы вы опубликовать здесь более подробный код, чтобы нам было легче помочь вам определить проблему?