Method returning value from asynchronous block with FacebookSDK

后端 未结 3 474
悲&欢浪女
悲&欢浪女 2020-12-18 11:03

What I am trying to do is a Facebook wrapper for the Facebook iOS SDK. Basically the idea is that my ViewController should do nothing but showing ex. my friends that will be

相关标签:
3条回答
  • 2020-12-18 11:53

    I created a similar wrapper in the past and my approach was passing a "completion block" when calling my wrapper method; this completion block is then triggered once all the asynchronous calls are done running, and it receives whatever data your method would return in a synchronous scenario (in your case, the array of friends).

    To illustrate - you could have your "myFriends" method redefined as:

    + (void)myFriendsWithCompletionBlock:(void (^)(NSArray *friends))completionBlock;

    Then in the implementation, right after the friends = [NSArray arrayWithArray:fbFriends]; line, you would add this:

    if (completionBlock != nil) {
        completionBlock(friends);
    }
    

    ... and remove the return statement at the end.

    Finally, on your view controller (or any object using the method, you would do something like this:

    [FacebookWrapper myFriendsWithCompletionBlock:^(NSArray *friends){
        // do what you need to do with the friends array
    }];
    

    Of course, this is still asynchronous - but there's no way around since that's how the Facebook SDK was build (and, to be fair, this is probably the best way to do it - waiting for requests to finish synchronous would be terrible!)

    Edit: I noticed you're also returning from the wrapper method in case it fails; in that situation, instead of returning you would do something like this:

    if (completionBlock != nil) {
        completionBlock(nil);
    }
    

    That would cause the friends array to be nil when your completion block is called - you can then treat that error there however seems appropriate to you.

    Hope this helped!

    0 讨论(0)
  • 2020-12-18 11:53

    Think you need to use a protol @class Webservice;

    @protocol WebserviceDelegate
    @optional
    
    -(void)webservice:(Webservice *)webservice didFetchPosts:(NSArray *)posts;
    -(void)webservice:(Webservice *)webservice didFetchComments:(NSArray *)comments forPostID:(NSString *)postID launchComments:(BOOL)launch;
    -(void)webservice:(Webservice *)webservice didLoginWithUser:(User *)user;
    -(void)webservice:(Webservice *)webservice didVoteWithSuccess:(BOOL)success forObject:(id)object direction:(BOOL)up;
    
    @end
    
    @interface Webservice : NSObject {
        __weak id <WebserviceDelegate> delegate;
    }
    //Delegate
    @property (weak) id <WebserviceDelegate> delegate;
    
    
    
    -(void)getHomepage {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSURLResponse *response;
            NSError *error;
    
            // Create the URL Request
            NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:@"https://www.hnsearch.com/bigrss"]];
    
            // Start the request
            NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
    
            //Handle response
            //Callback to main thread
            if (responseData) {
                NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSStringEncodingConversionAllowLossy];
    
                if (responseString.length > 0) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self parseIDsAndGrabPosts:responseString];
                    });
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [delegate webservice:self didFetchPosts:nil];
                    });
    
                }
            }
            else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [delegate webservice:self didFetchPosts:nil];
                });
            }
    
    
        });
    }
    
    
    -(void)parseIDsAndGrabPosts:(NSString *)parseString {
        // Parse String and grab IDs
        NSMutableArray *items = [@[] mutableCopy];
        NSArray *itemIDs = [parseString componentsSeparatedByString:@"<hnsearch_id>"];
        for (int xx = 1; xx < itemIDs.count; xx++) {
            NSString *idSubString = itemIDs[xx];
            [items addObject:[idSubString substringWithRange:NSMakeRange(0, 13)]];
        }
    
    
        // Send IDs back to HNSearch for Posts
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSURLResponse *response;
            NSError *error;
    
            // Create Request String
            NSString *requestString = @"http://api.thriftdb.com/api.hnsearch.com/items/_bulk/get_multi?ids=";
            for (NSString *item in items) {
                requestString = [requestString stringByAppendingString:[NSString stringWithFormat:@"%@,", item]];
            }
    
            // Create the URL Request
            NSMutableURLRequest *request = [Webservice NewGetRequestForURL:[NSURL URLWithString:requestString]];
    
            // Start the request
            NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
    
            //Handle response
            //Callback to main thread
            if (responseData) {
                NSArray *responseArray = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error];
    
                if (responseArray) {
                    NSMutableArray *postArray = [@[] mutableCopy];
                    for (NSDictionary *dict in responseArray) {
                        [postArray addObject:[Post postFromDictionary:dict]];
                    }
    
                    NSArray *orderedPostArray = [self orderPosts:postArray byItemIDs:items];
    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [delegate webservice:self didFetchPosts:orderedPostArray];
    
                        // Update Karma for User
                        if ([HNSingleton sharedHNSingleton].User) {
                            [self reloadUserFromURLString:[NSString stringWithFormat:@"https://news.ycombinator.com/user?id=%@", [HNSingleton sharedHNSingleton].User.Username]];
                        }
                    });
                }
                else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [delegate webservice:self didFetchPosts:nil];
                    });
    
                }
            }
            else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [delegate webservice:self didFetchPosts:nil];
                });
            }
    
    
        });
    }
    
    0 讨论(0)
  • 2020-12-18 11:58

    If you are dispatching an asynchronouos block, you can communicate with your UIViewController subclass by calling back to it:

    [self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack];
    

    This will call self to get captured by the block, and so will work as expected. From the relevant method you can refresh the view / reload the tableview / dance a jig as required.

    Depending on the context, you may need to __block scope self, eg

    __block UIViewController *bsself = self;
    

    But if you do the latter, be careful to avoid a retain loop (the build and analysis tools are fairly good at pointing this out).

    0 讨论(0)
提交回复
热议问题