我正在研究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,但决定不再花时间尝试设置它 - 我按照说明书写了这封信,但它仍会引发错误。
答案 0 :(得分:3)
我已使用递归函数调用来解决此问题,并且我已将下限设置为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);
}
答案 1 :(得分:0)
这主要是基于我使用试错法进行的研究,因为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)
这会向Fb询问每张专辑中的照片数量及其ID。请注意,JSON回复的第1级包含用户的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。不!由于某种原因,这将无法按预期工作 - 它仍然指导我们到第一批而不是下一批。 但是,“下一个”链接仍然有效,因此可以使用它的一部分而不是我们对Graph Explorer进行的调用。因此,获得照片的电话:
<album_id>?fields=photos.fields(source,picture)
变为:
<album_id>/photos?fields=source%2Cpicture&limit=25
此外,它在附加&amp; after =:
后仍然有效<album_id>/photos?fields=source%2Cpicture&limit=25&after=
因此,在批次的每次调用中简单地获取“next”的值很容易,并将其附加到上面的字符串以进行下一次调用。
以下是代码最终版本的片段:
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;
}
答案 2 :(得分:0)
对于facebook的分页,我建议使用Apple本地类作为
如果nextPageURL不是nil,则使用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.
}
}
}];