mahieddine
mahieddine

Reputation: 565

FaceBook iOS SDK Batch Request & Single Completion Handler

I started to use Facebook SDK for iOS and i'm a little bit confused,

I'm seeing this little piece of code that shows how we can perform a batch request however having a completion handler per request is absurd for me. how can you make a completion handler per request when you make a single batch request ? maybe i didn't get the concept ? there is for sure an explanation for this but i don't see it right now

if ([[FBSDKAccessToken currentAccessToken] hasGranted:@"user_likes"]) {
  FBSDKGraphRequest *requestMe = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"me" parameters:nil];
  FBSDKGraphRequest *requestLikes = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"me/likes" parameters:nil];
  FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
  [connection addRequest:requestMe
           completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
   //TODO: process me information
}];
  [connection addRequest:requestLikes
            completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    //TODO: process like information
  }];
  [connection start];
}

If it is the only way to do it how can i know when all my requests have been performed ?

Upvotes: 1

Views: 402

Answers (2)

deRonbrown
deRonbrown

Reputation: 645

I created an FBBatchHandler class to automatically combine results and return a single completion handler to the caller. Source and example usage below. It's currently designed specifically for retrieving events (i.e. the final result is an NSArray of events), but it should be easily to repurpose it for other tasks. Let me know if this works for you.

FBBatchHandler.h

#import <Foundation/Foundation.h>
#import "FBSDKGraphRequestConnection.h"

typedef void (^BatchFinishedHandler)(NSArray *result, NSError *error);

@interface FBBatchHandler : NSObject

- (instancetype)initWithConnection:(FBSDKGraphRequestConnection *)connection
                   finishedHandler:(BatchFinishedHandler)finishHandler;

- (void)addRequestResult:(id)result;

@end

FBBatchHandler.m

#import "FBBatchHandler.h"

@interface FBBatchHandler () <FBSDKGraphRequestConnectionDelegate>

@property (nonatomic, strong) FBSDKGraphRequestConnection *connection;
@property (nonatomic, strong) BatchFinishedHandler finishHandler;
@property (nonatomic, strong) NSMutableArray *batchResults;

@end

@implementation FBBatchHandler

#pragma mark - Instance

- (instancetype)initWithConnection:(FBSDKGraphRequestConnection *)connection
                   finishedHandler:(BatchFinishedHandler)finishHandler {
    if (self = [super init]) {
        _connection = connection;
        _connection.delegate = self;
        _finishHandler = finishHandler;
        _batchResults = [NSMutableArray new];
    }

    return self;
}

#pragma mark - Public methods

- (void)addRequestResult:(id)result {
    if ([result isKindOfClass:[NSDictionary class]]) {
        [self.batchResults addObjectsFromArray:result[@"data"]];
    }
}

#pragma mark - FBSDKGraphRequestConnectionDelegate

- (void)requestConnectionDidFinishLoading:(FBSDKGraphRequestConnection *)connection {
    self.finishHandler([self.batchResults copy], nil);
}

- (void)requestConnection:(FBSDKGraphRequestConnection *)connection
         didFailWithError:(NSError *)error {
    self.finishHandler([self.batchResults copy], error);
}

@end

Example Usage

- (void)retrieveEvents {
    NSDictionary *params = @{@"since": @"now", @"fields": @"id,name,description,start_time,end_time,location,picture"};
    FBSDKGraphRequest *attending = [[FBSDKGraphRequest alloc] initWithGraphPath:@"/me/events/attending" parameters:params];
    FBSDKGraphRequest *created = [[FBSDKGraphRequest alloc] initWithGraphPath:@"/me/events/created" parameters:params];
    FBSDKGraphRequest *maybe = [[FBSDKGraphRequest alloc] initWithGraphPath:@"/me/events/maybe" parameters:params];
    FBSDKGraphRequest *notReplied = [[FBSDKGraphRequest alloc] initWithGraphPath:@"/me/events/not_replied" parameters:params];

    FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
    FBBatchHandler *batchHandler = [[FBBatchHandler alloc] initWithConnection:connection
                                                              finishedHandler:^(NSArray *result, NSError *error) {
                                                                  // Here's the "single" completion handler
                                                          }];
    [connection addRequest:attending
         completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             [batchHandler addRequestResult:result];
         }];
    [connection addRequest:created
         completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             [batchHandler addRequestResult:result];
         }];
    [connection addRequest:maybe
         completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             [batchHandler addRequestResult:result];
         }];
    [connection addRequest:notReplied
         completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             [batchHandler addRequestResult:result];
         }];
    [connection start];
}

Upvotes: 2

Tobi
Tobi

Reputation: 31479

Why don't you use just one request? In your case, it's not necessary to have two.

Use something like

/me?fields=id,name,likes

Upvotes: 0

Related Questions