使用反对时,自定义协议的实现因无法识别的选择器而崩溃
我正在定义一个自定义协议:
@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
我设置了 Objection 以从我的类绑定到协议。
@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
。我尝试显式构造 [[NGSFacebookAuthProvider alloc] init]
而不是使用 Objection 但它仍然崩溃。
我尝试使用 objc/runtime.h 方法循环遍历选择器以查看有哪些选择器,但它找到的唯一东西是初始化:
- (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);
}
这必须是简单的事情,我我失踪了。我使用 Cocoa 定义的协议,没有这个问题。我已经为基于 UIViewController 的委托定义了自定义协议,没有任何问题。
我很困惑为什么 Obj-C 运行时找不到我的方法!如果我将 idNGSFacebookAuthProvider
并显式构造它,那么一切都会起作用。
解决方案:
问题是我误解了如何绑定到协议。一种有效的方法是:
@implementation NGSObjectionModule
- (void)configure
{
[self bind:[[[NGSFacebookAuthProvider alloc] init] autorelease] toProtocol:@protocol(NGSAuthProvider)];
}
@end
我想做的是将一个类绑定到一个协议,但 Objection 可能不知道要调用的初始化程序?
I am defining a custom protocol:
@protocol NGSAuthProvider <NSObject>
- (BOOL)isReady;
- (BOOL)isSessionValid;
- (void)login;
- (void)logout;
- (NSString *)accessToken;
- (BOOL)handleOpenURL:(NSURL *)url;
@end
I want to have different providers. So one is a Facebook provider:
@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
I setup Objection to bind from my class to the protocol.
@interface NGSObjectionModule : ObjectionModule
@end
@implementation NGSObjectionModule
- (void)configure
{
self bind:[NGSFacebookAuthProvider class] toProtocol:@protocol(NGSAuthProvider)];
}
@end
I setup the Global Injector:
@implementation NGSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
ObjectionModule *module = [[NGSObjectionModule alloc] init];
ObjectionInjector *injector = [Objection createInjector:module];
[module release];
[Objection setGlobalInjector:injector];
}
I am using this in my RootViewController like this:
@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
When I run this, I get the following error:
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
So my class implements the protocol. It successfully is assigned to id<NGSAuthProvider>
. I tried contructing [[NGSFacebookAuthProvider alloc] init]
explicitly instead of using Objection and it still crashed.
I tried looping through the selectors using objc/runtime.h
methods to see which selectors are there but the only thing it finds is 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);
}
This has to be something simple that I am missing. I use protocols defined by Cocoa and don't have this issue. I have defined custom protocols for UIViewController
-based delegates without issue.
I am stumped as to why Obj-C runtime can't find my methods! If I change id<NGSAuthProvider>
to NGSFacebookAuthProvider
and construct it explicitly then it all works.
SOLUTION:
The problem was I misunderstood how to bind to a protocol. One way that works is:
@implementation NGSObjectionModule
- (void)configure
{
[self bind:[[[NGSFacebookAuthProvider alloc] init] autorelease] toProtocol:@protocol(NGSAuthProvider)];
}
@end
What I would like to do is bind a class to a protocol, but Objection probably wouldn't know the initializer to call?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是你试图使用静态类方法(表示因为你有一个+)而不是在你的对象实例上运行的方法(这就是你写的,带有 - )
The issue is you're trying to use the static class method (denoted because you've got a +) instead of a method run on an instance of your object (which is what you've written it as, with a -)
Chris,
您可以使用 Objection 的元类绑定,它允许您将元类绑定到协议并针对元类实例调用类方法。
例如,
但仅当您想使用类方法时。否则,您可以对共享实例使用协议绑定。
Chris,
You could use Objection's meta class bindings that allows you to bind a meta class to a protocol and invoke class methods against the meta class instance.
For example,
But only if you want to use class methods. Otherwise you can use the protocol bindings against a share instance.
我也遇到了同样的问题,因为我正在使用
它的正确工作方式是
I also faced the same issue as I was using
The right way for it to work is