处理Facebook用户照片的分页

我正在开发iOS应用程序的一项function,使用户可以从他们的Facebook图库中select一张照片。

我有最初的要求,让照片工作 – 它确实返回less量的照片和链接到下一批和上一批。 我的问题是我不知道处理这个分页的正确方法是什么; 我花了很长时间试图谷歌它或在Facebook的文件中find答案,但它只是垃圾(即没有任何帮助)。

你可以看看应该处理这个请求的方法,并向我解释如何将其余的照片添加到用户的FacebookPhotos可变数组?

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,但决定不花更多的时间来设置它 – 我按照指示信,但它仍然会抛出错误。

我已经使用recursion函数调用来解决这个问题,我已经设置了10的下限来testingfunction。

 -(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); } 

这主要是基于我使用试错法进行的研究,因为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); } }]; 

Facebookgraphics接受并以JSON回复。

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

一旦用户login,他们的会话由Facebook API在幕后处理,所以不需要担心,我们可以执行我们想要的特定请求。

要获取用户的相册数据,请将该string放入Graph Explorer中:

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

这将问Fb每张专辑中的照片数量和他们的ID。 请注意,JSON回复的第一个级别包含用户的ID以及包含“data”数组的“albums”数组 – 这是我们感兴趣的实际相册的数组。

拥有每个相册的ID我们可以探索他们的照片。 下面的电话将获得每张专辑的源照片及其缩图的链接:

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

哪里是您想要获得照片的相册的实际ID。

最初的问题是,由于专辑中可能会有很多照片,试图让他们一气呵成,这可能是一个坏主意 – 这就是为什么Facebook开始将分页引入这些电话。 这意味着你可以设置一次调用的照片数据的数量限制,然后你使用一个“光标”作为你想要获得的下一个/上一个批次,每个电话。 主要的问题是处理这样的分页数据。 如果我们查看之前调用中返回的数据,我们可以看到“分页”部分包含“游标”(包含“之前”和“之后”)和“下一个”。 “下一个”键是一个看起来非常类似于我们在graphics浏览器中使用的调用string的链接,它以“之后”光标结束; 那么我们可以认为可以简单地将“after”游标附加到我们的调用string上

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

并将其馈入Graph Explorer。 不! 出于某种原因,这不会按预期工作 – 它仍然指引我们到第一批,而不是下一个。 然而,“下一个”链接仍然有效,所以可以使用它的一部分,而不是我们对graphics浏览器的调用。 因此,获取照片的电话:

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

变为:

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

而且,在追加=之后还是有效的:

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

因此,在批次的每个调用中简单地获取“next”的值并将其附加到上一个string以便下一个调用很容易。

以下是代码的最终版本的片段:

 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; } 

对于Facebook的分页,我会build议使用苹果原生类

使用nextPageURLvariables来caching来自JSON响应的下一个url,并且如果nextPageURL不是nil并且使用下面的一段代码,则在下一个api请求上分配给urlstring:

  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. } } }];