【问题标题】:Handle pagination of Facebook user photos处理 Facebook 用户照片的分页
【发布时间】:2013-12-09 17:28:25
【问题描述】:

我正在为 iOS 应用开发一项功能,该功能将允许其用户从他们的 Facebook 相册中挑选照片。

我收到了让照片正常工作的初始请求 - 它确实返回了少量照片以及指向下一批和上一批的链接。我的问题是我不知道处理这种分页的正确方法是什么;我花了很长时间尝试在谷歌上搜索它或在 Facebook 的文档中找到答案,但这简直是垃圾(即没有任何帮助)。

您能否看一下应该处理此请求的方法并向我解释如何将其余照片添加到 usersFacebookPhotos 可变数组?

NSMutableArray *usersFacebookPhotos;

- (void) getUserPhotoAlbumsWithSuccess:(void (^) (bool))successHandler failure:(void (^) (NSError *error))failureHandler {

    usersFacebookPhotos = (NSMutableArray *)[[NSArray alloc] init];

    FBRequest *fbRequest = [FBRequest requestWithGraphPath:@"me?fields=photos.fields(picture,source)" parameters:nil HTTPMethod:@"GET"];
    [fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {

        if (!error) {

            NSLog(@"got the initial batch");
            // process the next batch of photos here
        }
        else {

            NSLog(@"error: %@", error);
        }
    }];
}

哦,是的 - 我尝试使用grabKit,但决定不再花时间尝试设置它 - 我按照信中的说明进行操作,但它仍然会抛出错误。

【问题讨论】:

    标签: ios objective-c facebook-graph-api pagination facebook-ios-sdk


    【解决方案1】:

    我使用递归函数调用来解决这个问题,并且我设置了 10 的下限来测试功能。

    -(void)facebookCall {   
        [self getFBFriends:@"me/friends?fields=name,picture.type(large)&limit=10"];
    }
    
    -(void)getFBFriends:(NSString*)url {
        [FBRequestConnection startWithGraphPath:url
                          completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
                              if (!error) {
                                  [self parseFBResult:result];
    
                                  NSDictionary *paging = [result objectForKey:@"paging"];
                                  NSString *next = [paging objectForKey:@"next"];
    
                                  // skip the beginning of the url https://graph.facebook.com/
                                  // there's probably a more elegant way of doing this
    
                                  NSLog(@"next:%@", [next substringFromIndex:27]);
    
                                  [self getFBFriends:[next substringFromIndex:27]];
    
                              } else {
                                  NSLog(@"An error occurred getting friends: %@", [error localizedDescription]);
                              }
                          }];
    }
    
    -(void)parseFBResult:(id)result {
    
        NSLog(@"My friends: %@", result);
    
        NSArray *data = [result objectForKey:@"data"];
        int j = 0;
        for(NSDictionary *friend in data){
            NSDictionary *picture = [friend objectForKey:@"picture"];
            NSDictionary *picData = [picture objectForKey:@"data"];
            NSLog(@"User:%@, picture URL: %@", [friend objectForKey:@"name"], [picData objectForKey:@"url"]);
            j++;
        }
        NSLog(@"No of friends is: %d", j);
    
    }
    

    【讨论】:

      【解决方案2】:

      这主要基于我使用试错法进行的研究,因为 Facebook 的文档根本没有帮助。我很高兴知道这样做的更好方法:)

      然后我们可以在模板代码中使用来自 Graph Explorer 的调用:

      NSString *yourCall = @”YourGraphExplorerCall”;
      
      FBRequest *fbRequest = [FBRequest requestWithGraphPath:yourCall parameters:nil HTTPMethod:@"GET"];
      [fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
      
      if (!error) {
      
          NSDictionary *jsonResponse = (NSDictionary *) result;
          // Do your stuff with the JSON response
      }
      else {
      
          failureHandler(error);
      }
      }];
      

      Facebook Graph 接受和回复 JSON。

      获取用户的相册和照片——分页问题

      一旦用户登录,他们的会话将由 Facebook API 在幕后处理,因此无需担心,我们只需执行我们想要的特定请求。

      要获取用户的专辑数据,请将此字符串放入 Graph Explorer:

      me?fields=albums.fields(count,id)
      

      这将要求 Facebook 提供每个相册中的照片数量及其 ID。请注意,JSON 回复的第一级包含用户的 ID 以及包含“data”数组的“albums”数组 - 这是我们感兴趣的实际专辑的数组。

      有了每个相册的 ID,我们就可以浏览他们的照片。以下调用将获取每个相册的源照片及其缩影的链接:

      <album_id>?fields=photos.fields(source,picture)
      

      您要获取其照片的相册的实际 ID 在哪里。

      最初的问题是,由于相册中可能有很多照片,因此尝试一次性获取它们可能是一个坏主意 - 这就是 Facebook 开发人员在这些调用中引入分页的原因。这意味着您可以为在单个呼叫中获得的照片数据数量设置限制,然后您可以使用“光标”来获取您想要获得的下一个/上一个批次,并将所述光标提供给您每次通话。 主要问题是处理这种分页数据。如果我们查看之前调用中返回的数据,我们可以看到有一个“分页”部分,其中包含“光标”(包含“之前”和“之后”)和“下一个”。 “next”键是一个链接,看起来与我们在 Graph Explorer 中使用的调用字符串非常相似——它以“after”光标结尾;那么,我们可以认为,可以简单地将“after”光标附加到我们的调用字符串

      <album_id>?fields=photos.fields(source,picture)&after=<after_cursor>
      

      并将其输入到图形资源管理器中。没有!由于某种原因,这不会按预期工作 - 它仍然将我们引导到第一批而不是下一批。 但是,“下一个”链接仍然有效,因此可以使用它的一部分来代替我们对 Graph Explorer 的调用。因此调用获取照片:

      <album_id>?fields=photos.fields(source,picture)
      

      变成:

      <album_id>/photos?fields=source%2Cpicture&limit=25
      

      而且,加上 &after=: 后它仍然有效:

      <album_id>/photos?fields=source%2Cpicture&limit=25&after=
      

      因此,很容易在批处理的每次调用中简单地获取“next”的值,并将其附加到上述字符串以进行下一次调用。

      这是最终版本代码的sn-p:

      NSString *const FACEBOOK_GRAPH_LIST_ALBUMS = @"me?fields=albums.fields(count,id,name)";
      NSString *const FACEBOOK_GRAPH_LIST_ALBUM_PHOTOS = @"/photos?fields=source%2Cpicture&limit=25&after=";
      NSArray *currentUsersFacebookAlbums;
      
      - (void) getUserPhotosWithSuccess:(void (^) ())successHandler failure:(void (^) (NSError *error))failureHandler {
      
          FBRequest *fbRequest = [FBRequest requestWithGraphPath:FACEBOOK_GRAPH_LIST_ALBUMS parameters:nil HTTPMethod:@"GET"];
          [fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
      
              if (!error) {
      
                  NSDictionary *jsonResponse = (NSDictionary *) result;
                  currentUsersFacebookAlbums = (NSArray *) [[jsonResponse valueForKey:@"albums"] valueForKey:@"data"];
      
                  for (NSDictionary *currentAlbum in currentUsersFacebookAlbums) {
      
                      NSString *albumId = [currentAlbum valueForKey:@"id"];
                      [self getCurrentUserFacebookPhotosWithAlbum:albumId afterCursor:nil failure:^(NSError *error) {
                          failureHandler(error);
                      }];
                  }
      
                  successHandler();
              }
              else {
      
                  failureHandler(error);
              }
          }];
      }
      
      - (void) getCurrentUserFacebookPhotosWithAlbum:(NSString *) albumId afterCursor:(NSString *) afterCursor failure:(void (^) (NSError *error))failureHandler {
      
          if (afterCursor == nil) {
      
              afterCursor = @"";
          }
      
          NSString *fbGraphCall = [NSString stringWithFormat:@"%@%@%@", albumId, FACEBOOK_GRAPH_LIST_ALBUM_PHOTOS, afterCursor];
      
          FBRequest *fbRequest = [FBRequest requestWithGraphPath:fbGraphCall parameters:nil HTTPMethod:@"GET"];
          [fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
      
              if (!error) {
      
                  NSDictionary *jsonResponse = (NSDictionary *) result;
                  NSArray *currentPhotoBatch = (NSArray *) [jsonResponse valueForKey:@"data"];
      
                  // Go through the currently obtained batch and add them to the returned mutable array
                  for (NSDictionary *currentPhoto in currentPhotoBatch) {
      
                      [[CurrentUserDataHandler sharedInstance] addFacebookPhoto:currentPhoto];
                  }
      
                  // If there's a "next" link in the response, recur the method on the next batch...
                  if ([[jsonResponse valueForKey:@"paging"] objectForKey:@"next"] != nil) {
      
                      // ...by appending the "after" cursor to the call
                      NSString *afterCursor = [[[jsonResponse valueForKey:@"paging"] valueForKey:@"cursors"] valueForKey:@"after"];
                      [self getCurrentUserFacebookPhotosWithAlbum:albumId afterCursor:afterCursor failure:^(NSError *error) {
                          failureHandler(error);
                      }];
                  }
      
                  if ([[jsonResponse valueForKey:@"paging"] objectForKey:@"next"] != nil && [self isLastAlbum:albumId]) {
      
                      [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_FACEBOOK_PHOTOS object:nil];
                  }
              }
              else {
      
                  failureHandler(error);
              }
          }];
      }
      
      - (bool) isLastAlbum:(NSString *) albumId {
      
          for (NSDictionary *albumData in currentUsersFacebookAlbums) {
      
              if ([albumId isEqualToString:[albumData valueForKey:@"id"]] && [currentUsersFacebookAlbums indexOfObject:albumData] == [currentUsersFacebookAlbums count] - 1) {
      
                  return YES;
              }
          }
      
          return NO;
      }
      
      【解决方案3】:

      对于facebook的分页,我建议使用apple native class作为

      如果 nextPageURL 不为零,则使用 nextPageURL 变量缓存 JSON 响应中的下一个 url,并在下一个 api 请求上分配给 url 字符串,并使用以下代码:

       if (self.nextPageURL) {
          // urlString is the first time formulated url string
          urlString = self.nextPageURL;
      }
      NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
      [NSURLConnection sendAsynchronousRequest:request queue:networkQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
          if (error) {
              DDLogVerbose(@"FACEBOOK:Connection error occured: %@",error.description);
          }else{
              isRequestProcessing = NO;
              NSDictionary *resultData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
              DDLogVerbose(@"parsed data is %@",resultData);
              self.nextPageURL = resultData[@"paging"][@"next"];
      
              // do your customisation of resultData here.
              }
          }
      }];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-08
        • 1970-01-01
        相关资源
        最近更新 更多