3

我想要做的是 Facebook iOS SDK 的 Facebook 包装器。基本上这个想法是我的 ViewController 除了显示 ex 什么都不做。我的朋友将通过一个简单的电话获得,例如

self.friends = [FacebookWrapper myFriends];
[self.tableView reloadData];

我的包装器 myFriends 方法应该是这样的

+ (NSArray *)myFriends
{
   __block NSArray *friends = nil;
   [FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
    if(FB_ISSESSIONOPENWITHSTATE(status)) {
    [FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection *connection, id data, NSError *error) {
       CFRunLoopStop(CFRunLoopGetCurrent());
        if(error) {
            return;
        }
        NSArray *friendsData = (NSArray *)[data data];
        NSMutableArray *fbFriends = [NSMutableArray array];
        for(id friendData in friendsData) {
            Friend *friend = [Friend friendWithDictionary:friendData];
            fbFriends addObject:friend];
        }
        friends = [NSArray arrayWithArray:fbFriends];
    }];
    CFRunLoopRun();
    }
  }];
  return friends;
}

问题在于 openActiveSessionWithReadPermissions 和 startForMyFriendsWithCompletionHandler 是异步块,因此该方法在块完成其任务之前返回。

任何帮助将非常感激。

4

3 回答 3

3

我过去创建了一个类似的包装器,我的方法是在调用我的包装器方法时传递一个“完成块”;一旦所有异步调用完成运行,就会触发这个完成块,它会接收您的方法在同步场景中返回的任何数据(在您的情况下,是朋友数组)。

举例说明-您可以将“myFriends”方法重新定义为:

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

然后在实现中,就在该friends = [NSArray arrayWithArray:fbFriends];行之后,您将添加以下内容:

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

...并删除最后的return语句。

最后,在您的视图控制器(或任何使用该方法的对象上,您将执行以下操作:

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

当然,这仍然是异步的——但是没有办法,因为这就是 Facebook SDK 的构建方式(而且,公平地说,这可能是最好的方法——等待请求完成同步会很糟糕!)

编辑:我注意到你也从包装方法返回,以防它失败;在这种情况下,您不会返回,而是执行以下操作:

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

这将导致friends数组nil在您的完成块被调用时出现 - 然后您可以在那里处理该错误,但似乎适合您。

希望这有帮助!

于 2013-02-28T13:59:50.637 回答
0

如果你正在调度一个异步块,你可以UIViewController通过回调它来与你的子类进行通信:

[self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack];

这将调用self以被块捕获,因此将按预期工作。从相关方法中,您可以根据需要刷新视图/重新加载 tableview/跳舞。

根据上下文,您可能需要__block范围self,例如

__block UIViewController *bsself = self;

但是,如果您执行后者,请小心避免保留循环(构建和分析工具非常擅长指出这一点)。

于 2013-02-28T11:37:34.853 回答
0

认为您需要使用协议@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];
            });
        }


    });
}
于 2013-10-27T00:28:37.527 回答