问题
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
回答1:
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;
回答2:
I think there are two ways for you:
Don't use ARC and leave your code as it was
If you want to use ARC, be aware that delegates normally shouldn't be retained. But when using ARC, an ivar declaration like this:
id <FBFeedDelegate> delegate
defaults to
id <FBFeedDelegate> __strong delegate
So when you declare a property like this:
@property (readwrite, unsafe_unretained) id <FBFeedDelegate> delegate
The ivar should look like this:
id <FBFeedDelegate> __unsafe_unretained delegate
回答3:
I had the same problem but then I was able to make it work correctly under iOS 5.1 on XCode 4.3.2
Use this code in your .h file
@protocol AnimationManagerCountdownTimerDelegate <NSObject>
@required
-(void)countdownCompleted;
@end
@interface AnimationManager : NSObject{
....
}
@property (nonatomic, strong) id <AnimationManagerCountdownTimerDelegate> countdownTimerDelegate;
@end
Then in the .m file you simply synthesize:
@synthesize countdownTimerDelegate;
来源:https://stackoverflow.com/questions/7205064/custom-delegate-not-working