1

I'm using the Facebook v4 SDK in my iOS app. To get relevant information, I frequently use the [FBSDKProfile currentProfile] singleton. However, I also need the profile image to be readily accessible, and hence wrote a category to take of this.

This is the header file:

#import <FBSDKCoreKit/FBSDKCoreKit.h>

@interface FBSDKProfile (ProfileImage)

+(void)fetchProfileImageWithBlock:(void (^)(BOOL succeeded))handler;

@property (nonatomic, strong, readonly) UIImage *profileImage;

@end

Here's the implementation file:

#import "FBSDKProfile+ProfileImage.h"

@interface FBSDKProfile()

@property (nonatomic, strong, readwrite) UIImage *profileImage;

@end

@implementation FBSDKProfile (ProfileImage)

+(void)fetchProfileImageWithBlock:(void (^)(BOOL succeeded))handler {
    FBSDKProfile *currentProfile = [FBSDKProfile currentProfile];
    NSString *userId = currentProfile.userID;
    if (![userId isEqualToString:@""] && userId != Nil)
    {
        [self downloadFacebookProfileImageWithId:userId completionBlock:^(BOOL succeeded, UIImage *profileImage) {
            currentProfile.profileImage = profileImage;
            if (handler) { handler(succeeded); }
        }];
    } else
    {
        /* no user id */
        if (handler) { handler(NO); }
    }
}

+(void)downloadFacebookProfileImageWithId:(NSString *)profileId completionBlock:(void (^)(BOOL succeeded, UIImage *profileImage))completionBlock
{
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large", profileId]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                               if (!error)
                               {
                                   UIImage *image = [[UIImage alloc] initWithData:data];
                                   completionBlock(YES, image);
                               } else{
                                   completionBlock(NO, nil);
                               }
                           }];
}

@end

However, I'm getting this exception:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FBSDKProfile setProfileImage:]: unrecognized selector sent to instance

Why is this?

Erik
  • 2,500
  • 6
  • 28
  • 49
  • I think you are setting image before download is completed. – Ketan Parmar Apr 16 '16 at 19:54
  • Properties don't get auto-synthesized in categories. You have to write your own getter and setter and provide your own storage for the image. – dan Apr 16 '16 at 19:55
  • @dan could you please elaborate on this? Trying to synthesize it displays this error: **@synthesize not allowed in a category's implementation** – Erik Apr 16 '16 at 19:59

2 Answers2

0

you can use,

FBSDKProfilePictureView *profilePictureview = [[FBSDKProfilePictureView alloc]initWithFrame:_imageView.frame];
[profilePictureview setProfileID:result[@"id"]];
[self.view addSubview:profilePictureview];

refer this link for more details.

Community
  • 1
  • 1
Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
0

Problem

You have added the attribute readonly to your property profileImage. It means what it says :

You can only read it, so calling the setter will throw an exception.

Solution

Don't assign readonly attribute to profileImage

@property (nonatomic, strong) UIImage *profileImage;
meda
  • 45,103
  • 14
  • 92
  • 122
  • Oh I see. I'm using `[FBSDKProfile currentProfile].profileImage = profileImage;`, instead of `self.profileImage = profileImage` which would've been possible if it wasn't a singleton but rather a "normal" class instance? – Erik Apr 16 '16 at 20:09
  • it would work if the property was `readwrite` which you dont actually need to explicitly specify since it is the default – meda Apr 16 '16 at 20:15
  • Removed the `readonly` attribute now, but it still displays the same exception. It issues a warning which is as follows: "Property 'profileImage' requires method `profileImage` to be defined - use @dynamic or provide a method implementation in this category". I can't do `@synthesize` as it displays an error. How do you create the setter/getter then? – Erik Apr 16 '16 at 20:17
  • have you tried adding `@dynamic profileImage;` as suggested? – meda Apr 16 '16 at 20:22
  • I did yes, same result though suppressed warning – Erik Apr 16 '16 at 20:23
  • I got it working now, didn't need `@dynamic`. What I did was create the getter and setter methods using `objc_setAssociatedObject` and `objc_getAssociatedObject` together with a key defined like so: `static char const * const kProfileImageKey = "profile_image";`. Works like a charm! – Erik Apr 17 '16 at 12:07