繁体   English   中英

在另一个类 (scene.swift) 中引用我的视图控制器 - 所有变量都变为 null? 斯威夫特 3

[英]Referring to my view controller in another class (scene.swift) - all variables turn to null? Swift 3

我正在尝试从我的 Scene.swift 类中的视图控制器调用一个方法 - 我能够做到。 当我单击视图控制器中设置的 SKLabel 节点时,在调用 touchesBegan 方法之后调用该方法。

问题是当我点击一个 SKLabelNode 时,控制传递给 Scene.swift 类,在 touchesBegan 方法中,我想调用的方法被调用,所以当我回到这里时,控制被传递回视图控制器似乎我所有的变量都设置为 nil,好像它是一个完全不同的控制器实例?

当我尝试在 ArViewController 中设置标签的文本属性时,checkIfValidTime 方法中发生错误。 - 我用**突出显示了这些行。

错误:

Fatal error: Unexpectedly found nil while unwrapping an Optional value

我如何引用视图控制器的相同实例,以便在 Scene.Swift 中声明它时变量不会重置? 或者有没有一种方法可以在视图控制器中实现 touchesBegan 方法,这样我就不必实例化 ARViewController?

我很感激在这个问题上的任何帮助,因为我已经被困在这个问题上一段时间了,而且我是 iOS 和 swift 应用程序设计的新手。

我试图将代码限制在我解释这个问题所必需的范围内。 有什么问题就问吧。 谢谢

AR视图控制器:

    public var receivedCallback : Bool = false

    class ARViewController: UIViewController, ARSKViewDelegate, URLSessionDelegate {
        // MARK: - IBOutlets
        @IBOutlet weak var sceneView: ARSKView!
        @IBOutlet weak var guideLabel: UILabel!
        @IBOutlet weak var testLbl: UILabel!

 var scene : Scene?
        static var dateToUse : Date?
        var aRLocalDate : Date?

        var button: SKSpriteNode?

        override func viewDidLoad() {
            super.viewDidLoad()
        }

        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            /*
             Start the view's AR session with a configuration that uses the rear camera,
             device position and orientation tracking, and plane detection..
             */
            let configuration = ARWorldTrackingConfiguration()

            guard ARWorldTrackingConfiguration.isSupported else {
                fatalError(""
                    ARKit is not available on this device."")
            }
            sceneView.session.run(configuration)
            sceneView.delegate = self
            if let scene = SKScene(fileNamed: "Scene"){
                self.scene = scene as! Scene
                sceneView.presentScene(self.scene)
            } else {
                print("Error: scene initalisation failed")
            }
            let overflow = ((aRLocalDate?.debugDescription.count)! - 11)
            let endIndex = aRLocalDate?.debugDescription.index((aRLocalDate?.debugDescription.endIndex)!, offsetBy: -overflow)
            if let truncatedDate = aRLocalDate?.debugDescription.substring(to: endIndex!){
                DateLabel.text = truncatedDate
            }  
        }

        **/// - Tag: PlaceARContent**
        func view(_ view : ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
            if self.Generated == false{
                self.guideLabel.alpha = 0
                parentNode = SKShapeNode(rectOf: CGSize(width: 400, height: 720))
                var count = 1;
                for time in timesArray {
                    **//add a SKSpriteNode and assign image to it**
                    **let labelNode : SKLabelNode = SKLabelNode(text: time)**
                    labelNode.name = "booklabel" + String(count)
                    labelNode.isUserInteractionEnabled = false;
                    parentNode?.addChild(labelNode)
                    posy -= 60
                    count += 1
                }
                parentNode?.alpha = 0.6
                self.Generated = true

                drawEventNodes()
                return parentNode
            }
            else {
                return nil
            }
        }

        //check if the booking is not in the past
        func checkIfValidTime(bookingTime: String, startDateTimeDate: Date) -> Bool {
            thisDate = ARViewController.dateToUse;
            let date = Date()
            let currentHour = Calendar.current.component(.hour, from: date)
            if (startDateTimeDate > date) {
                print("Start time is greater than the current date. = valid")
               **self.guideLabel.text = "Test"**
                return true;
            }
            else {
                print("Start time is not valid - before current time")
                **self.guideLabel.text = "Test"**
                return false;
            }
        }

        func doPost(bookingTime: String) {
            print("Start of post method")
            thisDate = ARViewController.dateToUse;
            roomToBook = globalVariables.roomDictionary[globalVariables.userString]!
            let name = globalVariables.userString;
            let date = Date()
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"
            let displayName = globalVariables.userString
            let startDateStr = dateFormatter.string(from: thisDate!)
            let startHourString = bookingTime
            print("StartDateStr:", startDateStr)
            dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
            let startDateTimeString = "\(startDateStr)T\(startHourString)"
            let startDateTimeDate = dateFormatter.date(from: startDateTimeString)
            let endDateTimeDate = startDateTimeDate?.addingTimeInterval(3600)//3600 = 1 hour
            let endDateTimeString = dateFormatter.string(from: endDateTimeDate!)
            print("Start Date Time String", startDateTimeString)
            print("End date time string", endDateTimeString)
            print ("room to book: ",roomToBook)

            let valid = checkIfValidTime(bookingTime: bookingTime, startDateTimeDate: startDateTimeDate!)

            if (valid == true) {
                let jsonObject: [String: Any] =
                    [
                        "subject": "Booking",
                        "body":[
                            "contentType": "HTML",
                            "content": "Test Booking"
                        ],
                        "start":[
                            "dateTime": startDateTimeString,
                            "timeZone": "UTC"
                        ],
                        "end": [
                            "dateTime": endDateTimeString,
                            "timeZone": "UTC"
                        ],
                        "location":[
                            "displayName": displayName
                        ],
                        "attendees":[[
                            "emailAddress": [
                                "address": roomToBook,
                                "name": displayName
                            ],

                            "type": "required"
                            ]]
                ]

                //let valid = JSONSerialization.isValidJSONObject(jsonObject) // true
                let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject)

                // create post request
                let url = URL(string: "https://graph.microsoft.com/v1.0/me/events")!

                var request = URLRequest(url: url)
                request.setValue("Bearer \(globalVariables.accessToken)", forHTTPHeaderField: "Authorization")
                request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
                request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")        // the expected response is also JSON
                request.httpMethod = "POST"

                // insert json data to the request
                request.httpBody = jsonData

                let task = URLSession.shared.dataTask(with: request) { data, response, error in
                    guard let data = data, error == nil else {
                        print(error?.localizedDescription ?? "No data")
                        return
                    }
                    let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
                    if let responseJSON = responseJSON as? [String: Any] {
                        print(responseJSON)
                    }
                }

                task.resume()
                print("Post Done")
                print("Refreshing now")
                //code to refresh?

            }
            else {
                print("Invalid booking time - it is in the past.")
            }
        }    

场景.斯威夫特:

class Scene : SKScene{
    var controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ARStoryBoard") as! ARViewController
   // var controller: ARViewController!
    var bookingTime : String?

    override func touchesBegan(_ touches: Set<UITouch>, with event : UIEvent?) {
       // var c =  self.view?.window?.rootViewController as! ARViewController;

        for touch in touches {
            let location = touch.location(in: self)
            let node : SKNode = self.atPoint(location)
            let name = node.name
            switch name {
            case "booklabel1"?:
                controller.doPost(bookingTime: "08:00:00")
            case "booklabel2"?:
                controller.doPost(bookingTime: "09:00:00")
            case "booklabel3"?:
                controller.doPost(bookingTime: "10:00:00")
            case "booklabel4"?:
                controller.doPost(bookingTime: "11:00:00")
            case "booklabel5"?:
                controller.doPost(bookingTime: "12:00:00")
            case "booklabel6"?:
                controller.doPost(bookingTime: "13:00:00")
            case "booklabel7"?:
                controller.doPost(bookingTime: "14:00:00")
            case "booklabel8"?:
                controller.doPost(bookingTime: "15:00:00")
            case "booklabel9"?:
                controller.doPost(bookingTime: "16:00:00")
            case "booklabel10"?:
                controller.doPost(bookingTime: "17:00:00")
            case "booklabel11"?:
                controller.doPost(bookingTime: "18:00:00")
            default:
                print ("No Specific Label Clicked")
            }
        }
    }

}

试试这个。 检查更新的编辑答案:强烈推荐

ARViewController:在类外创建一个实例

weak var arViewControllerInstance = ARViewController()

确保在 ARViewController 类中初始化:

 override func viewDidLoad() {
            super.viewDidLoad()
            arViewControllerInstance = self
        }

现在您可以使用以下方法调用 Scene.Swift:

arViewControllerInstance?.doPost(bookingTime: "08:00:00")

编辑:强烈推荐

上述方法简单但强烈不推荐用于最佳实践。 看看下面使用委托协议的实现。

创建协议

protocol ScenceArViewControllerDelegate {
    func doPost(bookingTime: String)
}

在 ARViewController 类中添加上面的委托,如下所示。

class ARViewController: UIViewController, ScenceArViewControllerDelegate{
    func doPost(bookingTime: String){
       //Funcion body goes here
    }
}

在 Scene 类中创建一个委托变量,如下所示(Scene.swift)

class Scene: SKScene{
    weak var delegateARVC: ScenceArViewControllerDelegate?
}

一旦你首先实施。 现在您已经从ARViewController声明了delegateARVC变量,如下代码所示。 (注意:你可以使用依赖注入来设置值,但下面只设置对象)

class ARViewController: UIViewController, ScenceArViewControllerDelegate{

        var scene: Scene?
 
        override func viewDidLoad() {
            super.viewDidLoad()
            scene = Scene()
            scene.delegateARVC = self
        }

        func doPost(bookingTime: String){
           //Funcion body goes here
        }
    }
    

现在一切都很好。 现在,您的 Scene 类通过使用ScenceArViewControllerDelegate调用doPost的方法知道它与ARViewController有一个关系引用。

您可以从 Scene 类调用AARViewControllerdoPost方法,如下所示。

guard let delegateARCAvailable = delegateARVC else { return }
delegateARCAvailable.doPost(bookingTime: "08:00:00")

您可以根据需要申请。 谢谢。

@Liam 有“所有权链”。 “拥有”的意思是负责让对象保持活力。 示例图书馆、阅读器和书籍。 书有图书馆的印章,所以它有参考,但绝对书不拥有图书馆。 读者也一样。 但是图书馆和读者都声称拥有这本书。 如果没有人拿 Book to Read 声明所有权),并且图书馆被销毁 - 他们的书也被销毁。

在 Swift 中,它是通过strong引用和weak引用来实现的。 默认情况下,所有变量都是strong变量。

通常,您查看由应用程序委托或其他视图控制器(手动或使用故事板)实例化的控制器。 其他任何人都可以被视图控制器使用,并且可以了解视图控制器但不“拥有”它。 所以变量必须声明为weak 请注意,您不拥有weak ,因此它必须是可选的,并且可以随时取消(如果用户导航回来),因此您必须使用额外的保护。

总结一下:

1:在场景中声明你的viewController为weak:

class Scene : SKScene{
    weak var controller: ARViewController?
    ....*
}

2:为您的场景提供视图控制器。 您可以在创建场景或设置场景时执行此操作。 例如:

 class ARViewController: UIViewController, ARSKViewDelegate, URLSessionDelegate {
 //...
 var scene : Scene? {
    didSet{
       //Optional: In case you can change scenes - remove view controller from old scene 
       oldValue?.controller = nil
       //Actually set view controller of any scene it "own"
       scene?.controller = self
    }
 }

PS:有额外的修饰符“无主”。 但它是更先进的技术,可能会导致问题和崩溃。 我建议你让自己熟悉weak 习惯于guard保留周期,然后继续。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM