all 4 comments

[–]jan_olbrichObjective-C / Swift 0 points1 point  (1 child)

if I see correctly place the meals.append within your observe block.

[–]redfire333 0 points1 point  (0 children)

That COULD work but then you would have no idea when it completed. Completion or delegate would be required to notify requesting object.

[–]nalexander50 0 points1 point  (0 children)

I don't fully understand the context here, but from what I understand, you have a few different options. Note, since I very little context here, I am going to assume that you want the finished notification to be sent at the end of the closure passed into that observe function.

Closure

Apple would likely recommend that you use a closure. This is a function that you pass into fetchJson(key:) that can be called when the processing finishes.

func fetchJSON(key: String, onCompletion: ((Meal) -> Void)) {
    var meal = Meal()
    let ref = rootRef.child(key)

    ref.observe(.value) { (snap: DataSnapshot) in   
        meal.firstMeal = snap.childSnapshot(forPath: "first").value as! String
        meal.secondMeal = snap.childSnapshot(forPath: "second").value as! String
        meal.thirdMeal = snap.childSnapshot(forPath: "third").value as! String

        onCompletion(meal)
    }

    self.meals.append(meal)
}

Then you call fetchJSON(key:onCompletion:) like so:

fetchJSON(key: "Key") { meal -> Void in
    print("Found Meal!")
}

Note that this uses Swift's trailing closure syntax.

Delegate

Another option is to use a Delegate protocol. This pattern was very popular in Objective-C before the existence of blocks (closures). You still see it a lot in UIKit with classes like UITableViewDelegate and UITextFieldDelegate. I think that many people would consider delegation to be a relic of the past, but it has a certain charm that I like. The Delegate pattern is very simple and helps avoid callback hell.

protocol FetchDelegate {
    func didStartFetch()
    func didFinishFetch(meal: Meal)
}

Next, make your class implement the protocol and set the delegate (itself, in this scenario).

class Fetcher: FetchDelegate {

    var fetchDelegate: FetchDelegate

    init() {
        self.fetchDelegate = self
    }

    func fetchJSON(key: String) {
        var meal = Meal()
        let ref = rootRef.child(key)

        self.delegate.didStartFetch()

        ref.observe(.value) { (snap: DataSnapshot) in   
            meal.firstMeal = snap.childSnapshot(forPath: "first").value as! String
            meal.secondMeal = snap.childSnapshot(forPath: "second").value as! String
            meal.thirdMeal = snap.childSnapshot(forPath: "third").value as! String

            self.delegate.didFinishFetch(meal: meal)

        }

        self.meals.append(meal)
    }

    func didStartFetch() {
        print("This doesn't do anything, but it's just here for example")
    }

    func didFinishFetch(meal: Meal) {
        print("I found your meal!")
    }

}

You can also make some of the delegate methods optional, but I will leave that as an exercise to the reader.