2 votes

Si je me réfère à mon contrôleur de vue dans une autre classe (scene.swift), toutes les variables deviennent nulles ? Swift 3

J'essaie d'appeler une méthode depuis mon contrôleur de vue dans ma classe Scene.swift - ce que je peux faire. La méthode est appelée après l'appel de la méthode touchesBegan lorsque je clique sur un nœud SKLabel, qui sont configurés dans mon contrôleur de vue.

Le problème est que lorsque je clique sur un SKLabelNode, le contrôle passe à la classe Scene.swift et dans la méthode touchesBegan, la méthode que je veux appeler est appelée, donc le contrôle est renvoyé au contrôleur de vue, quand je reviens ici, il semble que toutes mes variables sont mises à zéro, comme si c'était une instance complètement différente du contrôleur ?

L'erreur se produit dans la méthode checkIfValidTime lorsque j'essaie de définir la propriété textuelle d'une étiquette dans le ArViewController. - J'ai mis en évidence ces lignes avec **.

Erreur :

Fatal error: Unexpectedly found nil while unwrapping an Optional value

Comment puis-je référencer la même instance du contrôleur de vue afin que les variables ne soient pas réinitialisées lorsque je le déclare dans le fichier Scene.Swift ? Ou existe-t-il un moyen d'implémenter la méthode touchesBegan dans le contrôleur de vue afin de ne pas avoir à instancier l'ARViewController ?

J'apprécierais toute aide à ce sujet car je suis bloqué depuis un moment maintenant et je suis nouveau dans la conception d'applications iOS et swift.

J'ai essayé de limiter le code à ce qui m'est nécessaire pour expliquer ce problème. Si vous avez des questions, n'hésitez pas à les poser. Merci

ARViewController :

    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.")
            }
        }    

Scène. Swift :

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")
            }
        }
    }

}

4voto

Pranavan Sp Points 648

Essayez ça.

ARViewController : Créer une instance en dehors de la classe

weak var arViewControllerInstance = ARViewController()

Assurez-vous de l'initialisation dans la classe ARViewController :

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

Maintenant, vous pouvez appeler dans Scene.Swift en utilisant :

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

1voto

MichaelV Points 1062

@Liam Il existe une "chaîne de propriété". "Posséder" signifie prendre la responsabilité de maintenir l'objet en vie. Exemple : bibliothèque, lecteur et livre. Le livre a le cachet de la bibliothèque, il y fait donc référence, mais il est certain que le livre ne possède pas la bibliothèque. Idem pour le lecteur. Mais Library et Reader revendiquent tous deux la propriété du livre. Si personne ne prend le livre pour le lire en déclarant sa propriété, et que la bibliothèque est détruite, le livre est également détruit.

En Swift, il est implémenté via strong y weak références. Toutes les variables sont strong par défaut.

Habituellement, les contrôleurs de vue sont instanciés par le délégué de l'application, ou par d'autres contrôleurs de vue (manuellement ou à l'aide du storyboard). N'importe qui d'autre peut être utilisé par les contrôleurs de vue, et peut être conscient du contrôleur de vue mais ne le "possède" pas. Ainsi, la variable doit être déclarée comme weak . N'oubliez pas que vous ne possédez pas weak Il devait donc être facultatif et pouvait être annulé à tout moment (si l'utilisateur revenait en arrière), d'où la nécessité d'utiliser une protection supplémentaire.

Pour résumer :

1 : Déclarez votre viewController dans la scène comme faible :

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

2 : Fournissez votre scène avec un contrôleur de vue. Vous pouvez le faire lors de la création de la scène, ou lors de son paramétrage. Par exemple :

 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 : il existe un modificateur supplémentaire "unowned". Mais c'est une technique plus avancée, qui peut causer des problèmes et des plantages. Je vous conseille de vous familiariser avec weak . Habituez-vous à guard conserver les cycles, puis continuer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X