djax djax - 2 months ago 10
Objective-C Question

Facebook Photo Downloading

I am attempting to download Facebook albums of photos from a user in my app. Unfortunately although I do have an access token, I am getting zero albums from the requests. I am not getting an error, just getting zero. Why? If you would like to see any more code or ask more questions, just ask. Note that I have authorized the current user's Facebook permissions when they signed up, and I've since quit the app and opened it many times (don't think this would be an issue, since I have an access token..?)

- (void)getAlbums:(OLFacebookAlbumRequestHandler)handler {
if ([FBSDKAccessToken currentAccessToken]) {
// connection is open, perform the request
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *graphPath = @"me/albums?limit=100&fields=id,name,count,cover_photo";
if (self.after) {
graphPath = [graphPath stringByAppendingFormat:@"&after=%@", self.after];

FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath parameters:nil];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (self.cancelled) {
if (error) {
[OLFacebookAlbumRequest handleFacebookError:error completionHandler:handler];

NSString *parsingErrorMessage = @"Failed to parse Facebook Response. Please check your internet connectivity and try again.";
NSError *parsingError = [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerBadResponse userInfo:@{NSLocalizedDescriptionKey: parsingErrorMessage}];
id data = [result objectForKey:@"data"];
if (![data isKindOfClass:[NSArray class]]) {
handler(nil, parsingError, nil);

NSMutableArray *albums = [[NSMutableArray alloc] init];
for (id album in data) {
if (![album isKindOfClass:[NSDictionary class]]) {

id albumId = [album objectForKey:@"id"];
id photoCount = [album objectForKey:@"count"];
id name = [album objectForKey:@"name"];

if (!([albumId isKindOfClass:[NSString class]] && [photoCount isKindOfClass:[NSNumber class]]
&& [name isKindOfClass:[NSString class]])) {

OLFacebookAlbum *album = [[OLFacebookAlbum alloc] init];
album.albumId = albumId;
album.photoCount = [photoCount unsignedIntegerValue]; = name;
album.coverPhotoURL = [NSURL URLWithString:[NSString stringWithFormat:@"", album.albumId, [FBSDKAccessToken currentAccessToken].tokenString]];
[albums addObject:album];

// get next page cursor
OLFacebookAlbumRequest *nextPageRequest = nil;
id paging = [result objectForKey:@"paging"];
if ([paging isKindOfClass:[NSDictionary class]]) {
id cursors = [paging objectForKey:@"cursors"];
id next = [paging objectForKey:@"next"]; // next will be non nil if a next page exists
if (next && [cursors isKindOfClass:[NSDictionary class]]) {
id after = [cursors objectForKey:@"after"];
if ([after isKindOfClass:[NSString class]]) {
nextPageRequest = [[OLFacebookAlbumRequest alloc] init];
nextPageRequest.after = after;

handler(albums, nil, nextPageRequest);
else {
NSString *message = @"No Facebook user authentication found.";
handler(nil, [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerNoOpenSession userInfo:@{NSLocalizedDescriptionKey: message}], nil);

//Code for fetching albums...
- (void)loadNextAlbumPage {
self.inProgressRequest = self.albumRequestForNextPage;
self.albumRequestForNextPage = nil;
[self.inProgressRequest getAlbums:^(NSArray/*<OLFacebookAlbum>*/ *albums, NSError *error, OLFacebookAlbumRequest *nextPageRequest) {
self.inProgressRequest = nil;
self.loadingIndicator.hidden = YES;
self.albumRequestForNextPage = nextPageRequest;

if (error) {
if (self.parentViewController.isBeingPresented) {
self.loadingIndicator.hidden = NO;
self.getAlbumError = error; // delay notification so that delegate can dismiss view controller safely if desired.
} else {
[self.delegate albumViewController:self didFailWithError:error];

NSMutableArray *paths = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < albums.count; ++i) {
[paths addObject:[NSIndexPath indexPathForRow:self.albums.count + i inSection:0]];

[self.albums addObjectsFromArray:albums];
if (self.albums.count == albums.count) {
// first insert request
[self.tableView reloadData];
} else {
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];

if (nextPageRequest) {
self.tableView.tableFooterView = self.loadingFooter;
} else {
self.tableView.tableFooterView = nil;


//And when they signed up:

[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{ @"fields" : @"id,first_name,photos,picture.width(400).height(400)"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) { //etc etc the method continues.


FB authentication will give you a unique access_token for a particular set of permissions. To access user photos, you need to request the user_photos permission. Use the FBSDKLoginButton to request permissions.

loginButton.readPermissions = @[@"public_profile", @"email", @"user_photos"];

Once you have an access token with the required permissions, persist that locally (on the device) to reuse in future. If the access code is still valid, you won't need to request it again. If it becomes invalid (in case the user explicitly revoked permissions to your app), send them back to the login screen.