Search code examples
iosobjective-casynchronousparse-platformparse-server

Parse-Server iOS SDK - Create function that returns results of PFQuery


There are multiple places within my app that I display a list of objects returned from the server. I'm trying to re-write some code so it only has to be modified in one place, rather than three, for updates.

The basic gist looks like this:

        PFQuery *query = [PFQuery queryWithClassName:"MyClass"];
        //query constraints
        [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
            if( !error ) //Do stuff with objects;
            else [self displayError:error];
        }];

I have subclassed PFObject for this class, so I have a class called MyClass. I was trying to put a class method on this class that returns an NSArray * containing the results of a query. However, the following function throws some errors:

+(NSArray *)getListOfMyClass {
    PFQuery *query = [PFQuery queryWithClassName:"MyClass"];
    //query constraints
    [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
        if( !error ) return objects;
        else [self displayError:error];
    }];
} 

This error appears at the end of the function: Control may reach end of non-void block

This error appears at return objects;: Incompatible block pointer types sending 'NSArray * _Nullable (^)(NSArray * _Nullable __strong, NSError * _Nullable __strong)' to parameter of type 'PFQueryArrayResultBlock _Nullable' (aka 'void (^)(NSArray<PFGenericObject> * _Nullable __strong, NSError * _Nullable __strong)')

So, I know this issue is due to the asynchronous behavior of this query. I need to call this query from a few different places, so was hoping I could call the single function, but now I'm lost as to how make this efficient and not very mucked up. I'm sorta leaning towards just doing it in line three times, as that's what I was doing already anyway, but I'm trying to learn better practices.

Is there a way I can force this function to wait to return until the query has succeeded? Or would it be OK to pass in sender, and then trigger a function on the sender that passes in the results? I'm gonna be working on the latter to see if it works, but even that seems so roundabout. I'm wondering if there's something obvious I'm missing.

Thanks for your help!

Note - I would prefer Objective C answers, but can work with a Swift answer if need be.


Solution

  • According to PFQuery.h :

    typedef void (^PFQueryArrayResultBlock)(NSArray<PFGenericObject> *_Nullable objects, NSError * _Nullable error);
    

    The findObjectsInBackgroundWithBlock is a void block which returns nothing, so obviously the return statement gonna cause error.

    If you want to retrieve the array, you can use a completion handler, like:

    +(void)getListOfMyClassWithCompletionBlock:(void (^)(NSError *error, NSArray *objectArray))block {
        PFQuery *query = [PFQuery queryWithClassName:"MyClass"];
        //query constraints
        [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
            if( !error ) block(nil, objects);
            else block(error, nil); [self displayError:error];
        }];
    }
    

    And somewhere else (other classes) in your code:

    [YourClass getListOfMyClassWithCompletionBlock:^(NSError *error, NSArray *objectArray) {
        if (!error) //update your UI with objectArray
    }];