我想要做的是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是异步块,因此该方法在块完成任务之前返回。
非常感谢任何帮助。
答案 0 :(得分: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
- 然后您可以在那里处理该错误,但这对您来说是合适的。
希望这有帮助!
答案 1 :(得分:0)
如果要调度异步块,可以通过回调它与UIViewController
子类进行通信:
[self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack];
这将调用self
以便被块捕获,因此将按预期工作。从相关方法中,您可以根据需要刷新视图/重新加载tableview /跳舞夹具。
根据具体情况,您可能需要__block
范围self
,例如
__block UIViewController *bsself = self;
但如果你选择后者,请小心避免使用保留循环(构建和分析工具相当擅长指出这一点)。
答案 2 :(得分:0)
认为你需要使用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];
});
}
});
}