Пользовательский делегат не работает

Я начал больше работать с делегатом, как это было предложено в другом вопросе, который я задал. Теперь я создал UIViewController с именем ProfileViewController, в который я хотел бы загрузить ленту новостей из Facebook. У меня также есть подкласс NSObject под названием FBFeed. Этот подкласс загружает ленту новостей Facebook и должен передать ее контроллеру представления. Все мои запросы к Facebook отправляются через синглтон с именем FBRequestWrapper, который (в данном случае) должен передавать результат FBFeed.

Я вызываю getFBRequestWithGraphPath:andDelegate: в FBRequestWrapper, который вызовет метод в Facebook iOS SDK, который принимает делегат в качестве параметра. Если я вставлю self (который будет FBRequestWrapper), он будет работать нормально. Если я введу _delegate (экземпляр FBFeed), приложение вылетит с EXC_BAD_ACCESS.

У меня есть теория, почему он может рухнуть. я прочитал это

@property (nonatomic, retain) id <FBFeedDelegate> delegate;

должно быть

@property (nonatomic, assign) id <FBFeedDelegate> delegate;

Но при этом я получаю следующую ошибку:

Существующий делегат ivar для свойства unsafe_unretained «делегат» должен быть __unsafe_unretained

Кроме того, я не знаю, достаточно ли этого для сбоя приложения.

Вот мой код.

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

person simonbs    schedule 26.08.2011    source источник
comment
Можете ли вы сказать, в какой строке встречается EXC_BAD_ACCESS?   -  person Dani    schedule 26.08.2011
comment
@Dani, я очень плохо использую инструмент точки останова, но кажется, что он проходит getFBRequestWithGraphPath:andDelegate: и происходит сбой на [self loadFeed] в ProfileViewController.m (эта строка должна вызываться перед getFBRequestWithGraphPath:AndDelegate, но, как уже упоминалось, я плохо использую инструмент отладки ). При сбое приложения UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); в main.m будет выделено.   -  person simonbs    schedule 26.08.2011
comment
Звучит правдоподобно, что ошибка может происходить внутри Facebook iOS SDK? Хотя, когда я разбираю его self (FBRequestWrapper), он работает нормально. Когда FBFeed является делегатом, он падает.   -  person simonbs    schedule 26.08.2011


Ответы (3)


Я предполагаю, что вы используете ARC и новый iOS5 SDK, который все еще находится под соглашением о неразглашении. Вместо сохранения используйте ключевое слово «сильный». Использование strong будет иметь такое же поведение, как и использование continue. Настройте свое свойство следующим образом:

@property (nonatomic, strong) id <FBFeedDelegate> delegate;

person Suhail Patel    schedule 26.08.2011
comment
Ах, конечно. Это заставило ошибку Existing ivar 'delegate'.... исчезнуть, но, к сожалению, приложение по-прежнему падает. - person simonbs; 26.08.2011
comment
@Suhail Patel: Если кто-то, кто заплатит Apple 100 долларов, сможет получить NDA sdk, я не уверен, сколько будет удерживать это NDA и действительно ли это что-то значит. - person Dani; 26.08.2011
comment
@Dani Я согласен, но это то, на что вы соглашаетесь, когда платите деньги Apple и регистрируетесь. Я думаю, будет ли это придерживаться, должны решить юристы, но вы не увидите широко распространенной информации и руководств, пока SDK не будут официально выпущены. До тех пор большая часть информации будет храниться на форумах разработчиков Apple. - person Suhail Patel; 26.08.2011

Я думаю, что у вас есть два пути:

  1. Не используйте ARC и оставьте свой код как есть

  2. Если вы хотите использовать ARC, имейте в виду, что делегаты обычно не должны сохраняться. Но при использовании ARC объявление ivar выглядит следующим образом:

id <FBFeedDelegate> delegate

по умолчанию

id <FBFeedDelegate> __strong delegate

Итак, когда вы объявляете свойство следующим образом:

@property (readwrite, unsafe_unretained) id <FBFeedDelegate> delegate

Ивар должен выглядеть так:

id <FBFeedDelegate> __unsafe_unretained delegate
person benjamin.ludwig    schedule 04.01.2012
comment
Кстати, я бы порекомендовал использовать ARC, потому что он дает некоторые большие преимущества, такие как меньше кода и, следовательно, меньше ошибок (особенно ошибок управления памятью, которые приводят к сбоям) и лучшая производительность. - person benjamin.ludwig; 04.01.2012

У меня была такая же проблема, но потом я смог заставить ее работать правильно под iOS 5.1 на XCode 4.3.2.

Используйте этот код в своем файле .h

@protocol AnimationManagerCountdownTimerDelegate <NSObject>
@required
    -(void)countdownCompleted;

@end


@interface AnimationManager : NSObject{
....
}

@property (nonatomic, strong) id <AnimationManagerCountdownTimerDelegate> countdownTimerDelegate;

@end

Затем в файле .m вы просто синтезируете:

@synthesize countdownTimerDelegate;
person Anil    schedule 13.05.2012