I have started working more with delegate as suggested in another question I made. Now, I have made a UIViewController called ProfileViewController in which I would like to load the News Feed from Facebook. I also have subclass of NSObject called FBFeed. This subclass loads the Facebook News Feed and should pass it back to the view controller. All my requests to Facebook are sent through a singleton named FBRequestWrapper which (in this case) should pass the result to FBFeed.
I call getFBRequestWithGraphPath:andDelegate: in FBRequestWrapper which will call a method in the Facebook iOS SDK which takes a delegate as a parameter. If I put in self (which will be the FBRequestWrapper) it works just fine. If I put in _delegate (which is an instance of FBFeed) the application crashes with EXC_BAD_ACCESS.
I have a theory why it might crash. I have read that
@property (nonatomic, retain) id <FBFeedDelegate> delegate;
should be
@property (nonatomic, assign) id <FBFeedDelegate> delegate;
But when doing so I get the following error:
Existing ivar ‘delegate’ for unsafe_unretained property ‘delegate’
must be __unsafe_unretained
Also, I don’t know if that enough to make the application crash.
Here is my code.
ProfileViewController.h
#import <UIKit/UIKit.h>
#import "FeedTableView.h"
#import "FBFeed.h"
@interface ProfileViewController : UIViewController <FBFeedDelegate>
{
FeedTableView *tableView;
}
- (void)loadFeed;
@end
ProfileViewController.m
@implementation ProfileViewController
- (void)loadFeed
{
FBFeed *feed = [[FBFeed alloc] init];
[feed loadNewsFeedWithDelegate:self];
}
#pragma mark -
#pragma FBFeedDelegate
- (void)finishedLoadingFeed:(FBFeed *)_feed
{
NSLog(@"ProfileViewController: FBFeed Finished.");
}
- (void)failedToLoadFeed:(FBFeed *)_feed
{
NSLog(@"ProfileViewController: FBFeed Failed.");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Load feed
[self loadFeed];
}
@end
FBFeed.h
#import <Foundation/Foundation.h>
#import "FBRequestWrapper.h"
@protocol FBFeedDelegate;
@interface FBFeed : NSObject <FBRequestDelegate>
{
id <FBFeedDelegate> delegate;
}
@property (nonatomic, retain) id <FBFeedDelegate> delegate;
- (void)loadNewsFeedWithDelegate:(id)_delegate;
@end
@protocol FBFeedDelegate <NSObject>
@required
- (void)finishedLoadingFeed:(FBFeed *)_feed;
- (void)failedToLoadFeed:(FBFeed *)_feed;
@end
FBFeed.m
#import "FBFeed.h"
@implementation FBFeed
@synthesize delegate;
- (void)loadNewsFeedWithDelegate:(id)_delegate
{
self.delegate = _delegate;
[[FBRequestWrapper defaultManager] getFBRequestWithGraphPath:@"me" andDelegate:self];
}
#pragma mark -
#pragma mark FBRequest Delegate
- (void)request:(FBRequest *)request didLoad:(id)result
{
NSLog(@"FBFeed: FBRequest Did Load.");
NSLog(@"%@", result);
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"FBFeed: FBRequest Failed.");
NSLog(@"%@", error);
}
@end
FBRequestWrapper.h
#import <Foundation/Foundation.h>
#import "FBConnect.h"
@interface FBRequestWrapper : NSObject <FBRequestDelegate, FBSessionDelegate>
{
Facebook *facebook;
BOOL isLoggedIn;
}
@property (nonatomic, assign) BOOL isLoggedIn;
+ (id)defaultManager;
- (void)setIsLoggedIn:(BOOL)_loggedIn;
- (void)FBSessionBegin:(id<FBSessionDelegate>)_delegate;
- (void)FBLogout;
- (void)getFBRequestWithGraphPath:(NSString *)_path andDelegate:(id)_delegate;
- (void)getFBRequestWithMethodName:(NSString *)_methodName andParams:(NSMutableDictionary *)_params andDelegate:(id)_delegate;
@end
FBRequestWrapper.m
#import "FBRequestWrapper.h"
static FBRequestWrapper *defaultWrapper = nil;
@implementation FBRequestWrapper
@synthesize isLoggedIn;
+ (id)defaultManager
{
if(!defaultWrapper)
{
defaultWrapper = [[FBRequestWrapper alloc] init];
}
return defaultWrapper;
}
- (void)getFBRequestWithGraphPath:(NSString *)_path andDelegate:(id)_delegate
{
if (_path != nil)
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (_delegate == nil)
{
_delegate = self;
}
[facebook requestWithGraphPath:_path andDelegate:_delegate];
}
}
#pragma mark -
#pragma mark FBRequestDelegate
- (void)request:(FBRequest *)request didLoad:(id)result
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"%@", result);
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"FBRequest Failed: %@", error);
}
@end
I guess you are using ARC and the new iOS5 SDK which is still under NDA. Instead of using retain, use the Keyword ‘strong’. Using strong will have the same behaviour intended as using retain. Set up your property like this:
@property (nonatomic, strong) id <FBFeedDelegate> delegate;