0

Currently I am attempting to push values into an array of note objects from firebase The only issue is due to Firebases asynchronous nature, I am having trouble getting the main thread to wait until the fetch function is completed. I have viewed many answers on this site and I have read up on the Semaphores and Dispatch queue documentation however I cannot get this fetch to work. It appears that most of the people here are attempting to use a table view which I am not.

Here is the fetch code

func fetchUser(){


FIRDatabase.database().reference().child("notes").observe(.childAdded, with: { (snapshot) in
        if let dictionary = snapshot.value as? [String: AnyObject] {
            let user = noteClass(dictionary: dictionary)
            self.coordinotes.append(user)
        }
    }, withCancel: nil)
} 

I have removed all of my semaphore and dispatch main attempts due to none of them working. This function is called in my view did load. When i check the values of my array that i push them into 'coordinotes' the value is not yet placed in and i get an out of bounds error.

Rest of code

import UIKit
import MapKit
import CoreLocation
import Firebase
import FirebaseDatabase

struct PreferencesKeys{
    static let savedItems = "savedItems"
}




class ViewController: UIViewController, CLLocationManagerDelegate{

    let manager = CLLocationManager()
    var coordinotes:[noteClass] = Array()
    var latitude = Double()
    var noteTime = noteBrain()

    //Map
    @IBOutlet weak var map: MKMapView!


    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
    {
        let location = locations[0]
        let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
        let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, noteTime.span)
        map.setRegion(region, animated: true)
        self.map.showsUserLocation = true
    }


    override func viewDidLoad()
    {
        super.viewDidLoad()
        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout))

        if FIRAuth.auth()?.currentUser?.uid == nil {
            perform(#selector(handleLogout), with: nil, afterDelay: 0)
        }
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
        fetchUser()
        loadAllCoordinotes()
    }

    func handleLogout() {

        do {
            try FIRAuth.auth()?.signOut()
        } catch let logoutError {
            print(logoutError)
        }

        let loginController = LoginController()
        present(loginController, animated: true, completion: nil)
    }

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


func loadAllCoordinotes() {
    let length = coordinotes.count - 1
    map.addAnnotation(coordinotes[length])
}
10
  • Not sure I understood your question but have you tried a completion handler? Commented Apr 18, 2017 at 0:12
  • Yes, i however the implementations I tried always dealt with a link to a database and were not placing the created data into an array. Do you by any chance have any further documentation I can look at? Commented Apr 18, 2017 at 0:13
  • Making the UI wait for a long operation to end is not the best way to do it. You should have a delegate method invoked when the operation ends just to inform you. Commented Apr 18, 2017 at 0:14
  • @JoséFonte would this delegate return true once the thread is finished? Then the rest of the code can continue? Commented Apr 18, 2017 at 0:15
  • Where do you declare coordinotes? Commented Apr 18, 2017 at 0:17

1 Answer 1

1
func fetchUser(_ completion:@escaping ([noteClass] , _ success: Bool)-> Void){
    let coordinotes = [noteClass]() 

FIRDatabase.database().reference().child("notes").observe(.childAdded, with: { (snapshot) in
        if let dictionary = snapshot.value as? [String: AnyObject] {
            let user = noteClass(dictionary: dictionary)
            coordinotes.append(user)
        }
        completion(coordinotes, true)
    }, withCancel: nil)

}

and then you call it in viewDidLoad like this:

  fetchUser { (coordinotes, success) in
            if success {
                self.coordinotes = coordinote
                self.loadAllCoordinotes()
            }
        }
Sign up to request clarification or add additional context in comments.

17 Comments

Thankyou for posting this. The first line is giving me an 'expected declaration' and is is telling me that "consecutive declarations must be separated by a ';'" I will try to play around with it.
try now. there was a typo, an extra ) at the end of the signature
The code compiled, however the value of "found" in loadAllCoordinotes is still not being printed which means it is still empty and the map is not displaying the pins. Also should it be self.coordinotes.append(user) on your line 6.
Through using a print statement during "if success" i have found that that if never executes. I will keep looking at it.
in the completion handler you return the array declared in line 2. Then in viewDidLoad you assign all the value to self. Have you tried to add a breakpoint to see if you are appending anything ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.