При использовании Objection реализация пользовательского протокола завершается с помощью нераспознанного селектора. - PullRequest
5 голосов
/ 27 июля 2011

Я определяю собственный протокол:

@protocol NGSAuthProvider <NSObject>
- (BOOL)isReady;
- (BOOL)isSessionValid;
- (void)login;
- (void)logout;
- (NSString *)accessToken;
- (BOOL)handleOpenURL:(NSURL *)url;
@end

Я хочу иметь разных провайдеров.Итак, один из них - провайдер Facebook:

@interface NGSFacebookAuthProvider : NSObject <NGSAuthProvider>
@end

@interface NGSFacebookAuthProvider () <FBSessionDelegate>
@property BOOL ready;
@property(nonatomic, retain) Facebook *facebook;
@property(nonatomic, retain) NSArray *permissions;
@end

@implementation NGSFacebookAuthProvider
//Implementation of fbLogin, fbLogout and the methods in NGSAuthProvider that forward calls to self.facebook
- (NSString *)accessToken
{
  return [self.facebook accessToken];
}

@end

Я настроил Возражение для привязки моего класса к протоколу.

@interface NGSObjectionModule : ObjectionModule
@end

@implementation NGSObjectionModule

- (void)configure 
{
   self bind:[NGSFacebookAuthProvider class] toProtocol:@protocol(NGSAuthProvider)];
}
@end

Я настроил глобальный инжектор:

@implementation NGSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ObjectionModule *module = [[NGSObjectionModule alloc] init];
  ObjectionInjector *injector = [Objection createInjector:module];
  [module release];

  [Objection setGlobalInjector:injector];
}

Я использую это в своем RootViewController следующим образом:

@interface RootViewController : UITableViewController
@end

@interface RootViewController ()
@property(nonatomic, retain) id<NGSAuthProvider> authProvider;
@end

@implementation RootViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  self.authProvider = [[Objection globalInjector] getObject:@protocol(NGSAuthProvider)];
}

- (void)processConfig {
  NSString *token = [self.authProvider accessToken];
  // use the access token
}
@end

Когда я запускаю это, я получаю следующую ошибку:

2011-07-26 21:46:10.544 ngs[6133:b603] +[NGSFacebookAuthProvider accessToken]: unrecognized selector sent to class 0x30c7c
2011-07-26 21:46:10.546 ngs[6133:b603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NGSFacebookAuthProvider accessToken]: unrecognized selector sent to class 0x30c7c'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00e825a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00fd6313 objc_exception_throw + 44
    2   CoreFoundation                      0x00e8417b +[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x00df3966 ___forwarding___ + 966
    4   CoreFoundation                      0x00df3522 _CF_forwarding_prep_0 + 50
    5   ngs                                 0x0000324b -[RootViewController processConfig] + 731
    6   ngs                                 0x000041a2 __33-[RootViewController viewDidLoad]_block_invoke_0 + 50

Итак, мой классреализует протокол.Он успешно назначен на id<NGSAuthProvider>.Я попытался сконструировать [[NGSFacebookAuthProvider alloc] init] явно вместо использования Objection , и он все еще зависнаходки initialize:

- (void)logSelectors:(id)obj
{
    int i=0;
    unsigned int mc = 0;
    Method * mlist = class_copyMethodList(object_getClass([obj class]), &mc);
    NSLog(@"%d methods", mc);
    for(i=0;i<mc;i++)
        NSLog(@"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));

    free(mlist);
}

Это должно быть что-то простое, что мне не хватает.Я использую протоколы, определенные Какао, и у меня нет этой проблемы.Я определил пользовательские протоколы для UIViewController делегатов без проблем.

Я озадачен тем, почему среда выполнения Obj-C не может найти мои методы!Если я изменю id<NGSAuthProvider> на NGSFacebookAuthProvider и создам его явно, то все это работает.

РЕШЕНИЕ:

Проблема заключалась в том, что я неправильно понял, как связываться с протоколом.Один из способов, который работает, это:

@implementation NGSObjectionModule

- (void)configure 
{
  [self bind:[[[NGSFacebookAuthProvider alloc] init] autorelease] toProtocol:@protocol(NGSAuthProvider)];
}
@end

Что я хотел бы сделать, это связать класс с протоколом, но, возможно, Objection не будет знать, что инициализатор должен вызывать?

Ответы [ 3 ]

0 голосов
/ 03 августа 2011

Крис,

Вы можете использовать привязки мета-класса Objection, которые позволяют привязывать мета-класс к протоколу и вызывать методы класса для экземпляра мета-класса.

Например,

[self bindMetaClass:[NGSFacebookAuthProvider class] toProtocol:@protocol(NGSAuthProvider)];

Но только если вы хотите использовать методы класса. В противном случае вы можете использовать привязки протокола к экземпляру общего ресурса.

0 голосов
/ 01 декабря 2015

Я также столкнулся с той же проблемой, что и при использовании

[self bind:[MyClass class] toProtocol:@protocol(MyProtocol)];

. Правильный способ его работы:

[self bindClass:[MyClass class] toProtocol:@protocol(MyProtocol)];
0 голосов
/ 27 июля 2011

Проблема в том, что вы пытаетесь использовать метод статического класса (обозначается потому, что у вас есть +) вместо метода, запущенного на экземпляре вашего объекта (что вы и написали, -)

...