【问题标题】:Method returning value from asynchronous block with FacebookSDK使用 FacebookSDK 从异步块返回值的方法
【发布时间】:2013-02-28 11:29:08
【问题描述】:

我想要做的是 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 是异步块,因此该方法在块完成任务之前返回。

任何帮助将不胜感激。

【问题讨论】:

    标签: ios objective-c xcode facebook-ios-sdk xcode4.6


    【解决方案1】:

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

    为了说明 - 您可以将“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 - 然后您可以在那里处理该错误,但似乎适合您。

    希望这有帮助!

    【讨论】:

    • 这正是我到目前为止一直在使用的逻辑(当然我会调用我的 completionBlock 以防出错)。但是,我想知道是否有任何方法可以返回从方法本身内的异步块获取的值。无论如何谢谢蒂亚戈!
    • 好的!不幸的是,没有办法做你想要达到的目标——至少不能完全控制所涉及的代码,因为我们谈论的是 Facebook SDK,你没有这些代码 :)
    【解决方案2】:

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

    [self someSelectorWithCallbackData:stuffWhichYouWantToGiveBack];
    

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

    根据上下文,你可能需要__block作用域self,例如

    __block UIViewController *bsself = self;
    

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

    【讨论】:

      【解决方案3】:

      认为您需要使用协议 @class 网络服务;

      @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];
                  });
              }
      
      
          });
      }
      

      【讨论】:

        猜你喜欢
        • 2011-09-06
        • 1970-01-01
        • 2012-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-28
        相关资源
        最近更新 更多