0

I created a unique ID with firebase using childByAutoID. I am able to print this ID from within the reference function used to create it, but when I assign the value to a class variable and print it in the console it comes out nil.

I am trying to send this data to another view controller using the override func prepareForSegue method. It works when the data is a string but it does not work when it is the variable holding the uniqueIDKey.

Here is the code:

class MainViewController: UIViewController, CLLocationManagerDelegate{

    var ref: FIRDatabaseReference!
    var refHandle: UInt!
    let locationManager = CLLocationManager()
    let regionRadius: CLLocationDistance = 1000
    var currentLocation: CLLocation!
    var location: CLLocationCoordinate2D!
    var latitude: Double!
    var longitude: Double!
    let geoCoder = CLGeocoder()
    var placemark: CLPlacemark?
    let date = NSDate()
    var currentOrderIDKey = ""



    @IBOutlet weak var mapView: MKMapView!
    @IBOutlet weak var userEmailLabel: UILabel!
    @IBOutlet weak var pickUpAddress: UITextField!
    @IBOutlet weak var deliveryAddress: UITextField!

    override func viewDidLoad() {
        ref = FIRDatabase.database().reference()



        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestLocation()
        locationManager.startUpdatingLocation()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest




        refHandle = ref.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
            let dataDict = snapshot.value as! [String: AnyObject]

            print((dataDict))
        })
        let userID: String = FIRAuth.auth()!.currentUser!.uid
        ref.child("users").child(userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
        let userEmail = snapshot.value!["email"] as! String
        self.userEmailLabel.text = userEmail
        })


        super.viewDidLoad()
        print("\(currentLocation)")
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("didFailWithError \(error)")

        if error.code == CLError.LocationUnknown.rawValue {
            return
        }
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        currentLocation = locations.last!
        latitude = currentLocation.coordinate.latitude
        longitude = currentLocation.coordinate.longitude
        location = CLLocationCoordinate2DMake(latitude, longitude)

        print("didUpdateLocations \(currentLocation.coordinate)")

        if currentLocation.timestamp.timeIntervalSinceNow < -10 {
            return
        }
        let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0)
        mapView.setRegion(coordinateRegion, animated: false)
    }





    @IBAction func requestPickUpButton(sender: AnyObject) {
        ref = FIRDatabase.database().reference()
        let userID: String = FIRAuth.auth()!.currentUser!.uid
        ref.child("users").child(userID).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
        let orderRef = self.ref.child("users").child(userID).child("orders")
        let origin = self.pickUpAddress.text!
        let destination = self.deliveryAddress.text!
        let orderID = orderRef.childByAutoId()
        let formatter = NSDateFormatter();
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ";
        let defaultTimeZoneStr = formatter.stringFromDate(self.date)
        let order = ["date": defaultTimeZoneStr, "origin": origin, "destination": destination]
        orderID.setValue(order)
        self.currentOrderIDKey = orderID.key as String
        print(self.currentOrderIDKey) ///This works!
        self.performSegueWithIdentifier("ServiceConfirmation", sender: self)
        self.locationManager.stopUpdatingLocation()
        })

        print(currentOrderIDKey) //this doesnt
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "ServiceConfirmation" {
            let destinationConroller = segue.destinationViewController as! UINavigationController
            let targetController = destinationConroller.topViewController as! ServiceConfirmationViewController
            targetController.currentOrderIDKey = "this works"
          //this does not :   targetController.currentOrderIDKey = currentOrderIDKey
        }
    }


    @IBAction func signOutButton(sender: AnyObject) {
        try! FIRAuth.auth()!.signOut()
        if let storyboard = self.storyboard {
            let viewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
            self.presentViewController(viewController, animated: false, completion: nil)
        }
    }
}

As a bonus question, I get this warning in the console every time I run the app:

<UILayoutContainerView: ...; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: ....>; layer = <CALayer: ....>>'s window is not equal to <UINavigationController: ....>'s view's window!

Thanks in advance!

cosmos
  • 153
  • 1
  • 15

1 Answers1

1

This is another classic case of Asynchrounous calls, you are accessing the value of currentOrderIDKey in print(currentOrderIDKey) even before it has been assigned.

Your print(currentOrderIDKey) line gets called even before

self.currentOrderIDKey = orderID.key as String
    print(self.currentOrderIDKey) ///This works!

gets called.

ref.child("users").child(userID).observeSingleEventOfType(.Value,.. sends a Asynchronous call to your backend which takes some time to retrieve the data, but even before you data could be retrieved your print(currentOrderIDKey) gets called resulting in null

Instead of segueing through performSegue.... use instantiation:-

let secondScene = self.navigationController?.storyboard?.instantiateViewControllerWithIdentifier("ServiceConfirmationViewControllerVC_ID") as! ServiceConfirmationViewController

  secondScene.valueTranfered = self. currentOrderIDKey
  self.navigationController?.pushViewController(secondScene, animated: true)

Where ServiceConfirmationViewControllerVC_ID is your secondScene storyBoardID

Might i suggest reading this:- Wikipedia : Asynchronous calls & https://stackoverflow.com/a/748189/6297658

Community
  • 1
  • 1
Dravidian
  • 9,945
  • 3
  • 34
  • 74