2

I am programming an app which utilizes a parse-server (hosted by heroku) database. I have several functions which pull information from the DB, but they are all inherently asynchronous (because of the way parse's .findObjectinBackground works.) The issue with this as that the later DB queries require information from previous queries. Since the information being pulled is asynchronous, I decided to implement PromiseKit to ensure that the object has been found from findObjectinBackground from the first query, before running the second query. The general form of the queries is as follows:

let query = PFQuery(classname: "Hello")
query?.findObjectsInBackground(block: { (objects, error) in
       if let objectss = objects{
           for object in objectss{ //object needs to be pulled
               arrayOfInterest.append(object)
               //array must be appended before moving on to next query

            }
        }            
})

I just do not know how exactly to do this. This is the way I would like to implement it:

import PromiseKit
override func viewDidLoad(){
    when(/*query object is retrieved/array is appended*/).then{
        //perform the next query
    }
}

I simply don't know exactly what to put in the when() and the .then{}. I tried making the queries into their own individual functions and calling them inside those two (when and then) functions, but I basically get told that I cannot because they return void. Also, I cannot simply ensure the first query is run in the when() as the query.findObjectinBackground(in the query) being asynchronous is the issue. The object specifically needs to be pulled, not just the query run, before the next one can fire.

Runeaway3
  • 1,439
  • 1
  • 17
  • 43

1 Answers1

1

Do you want create your promise?

You need write a function that return a Promise<Any>. In your case, need to encapsulate the entire code inside of Promise { fulfill, reject in HERE}. For example:

func foo(className: String) -> Promise<[TypeOfArrayOfInterest]> {
    return Promise { fulfill, reject in

        let query = PFQuery(classname: className)
        query?.findObjectsInBackground(block: { (objects, error) in
            if let error = error {
                reject(error) // call reject when some error happened
                return
            }

            if let objectss = objects {
                for object in objectss{
                    arrayOfInterest.append(object)
                }

                fulfill(arrayOfInterest) // call fulfill with some value
            }
        })

    }
}

Then, you call this function in firstly:

firstly {
    foo(className: "Hello")
}.then { myArrayOfInterest -> Void in
    // do thing with myArrayOfInterest
}.catch { error in
    // some error happened, and the reject was called!
}

Also, I wrote a post in my blog about, among other things, PromiseKit and architecture. It may be helpful: http://macalogs.com.br/ios/rails/ifce/2017/01/01/experiencias-eventbee.html

Edit

More complete example:

func foo() -> Promise<Int> {
    ...
}

func bar(someText: String) -> Promise<String> {
    ...
}

func baz() -> Promise<Void> {
    ...
}

func runPromises() {
    firstly {
        foo()
    }.then { value -> Promise<Any> in
        if value == 0 {
            return bar(someText: "no")
        } else {
            return bar(someText: "yes")
        }
    }.then { _ /* I don't want a String! */ -> Promise<Void> in
        baz()
    }.catch { error in
       // some error happened, and the reject was called!
    }
}

Or if you don't want a catch:

_ = firstly {
    foo()
}.then { _ in
    // do some thing
}

Swift have a greate type inference, but, when use PromiseKit, I recommend always write a type in then closure, to avoid erros.

macabeus
  • 4,156
  • 5
  • 37
  • 66
  • I understand your answer, but do I need to use the result of `foo()` in the `.then` statement? I just want to make sure `foo()` runs (and appends the array), and then with the `.then` I'd just like to run another query. Is that doable? – Runeaway3 Mar 19 '17 at 23:39
  • just to illustrate what I meant by the previous comment, what I eseentially want is: `firstly { foo() }.then { _ in otherQuery() }.then { _ in thirdQuery() }. catch {error in print(error) }` – Runeaway3 Mar 19 '17 at 23:45
  • @AlekPiasecki Yes, you can to make it, but, maybe do you need write explicitly a return type, in this case, `then { _ -> Promise in ... }`. I edited my answer, to exemplify . – macabeus Mar 20 '17 at 00:54