我在ShareKit中遇到了这段代码,我不明白作者在类方法中使用self
的想法。存在警告:将"Class"发送到参数类型id<FBSessionDelegate>
的指针类型不兼容我想清理这些警告,这样我就可以看到以后可能会受伤的警告。我能/应该做什么才不会打破这个
这是文件SHKFacebook.m,类名是SHKFacebook
+ (void)logout
{
FBSession *fbSession;
if(!SHKFacebookUseSessionProxy){
fbSession = [FBSession sessionForApplication:SHKFacebookKey
secret:SHKFacebookSecret
delegate:self];
}else {
fbSession = [FBSession sessionForApplication:SHKFacebookKey
getSessionProxy:SHKFacebookSessionProxyURL
delegate:self];
}
[fbSession logout];
}
self
可以在类方法中用作多态类实例。
因此,类方法new
可以这样实现:
+ (id)new
{
return [[self alloc] init];
}
并将返回消息中Class实例的正确类型:
例如:
NSArray * a = [NSArray new]; // << a is an NSArray
例如b:
NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray
请参阅下面的注释。
因此,您真正面临的是确保协议中只有实例方法,并且(类)自身的方法映射为采用协议中的实例方法。
就设计而言。。。好吧,就说我不会这样写吧。单身汉会更清晰、更正确,但我甚至不喜欢单身汉,所以我不会走那条路。
之所以生成警告,是因为Class实例(传递的内容)确实采用了delegate
参数指定的@protocol
。Class
实例不是该类的实例。协议声明真正适用于类的实例。例如,如果您采用NSLocking
,编译器是否希望您也为协议中声明的每个实例方法实现类方法?回答:从来没有。你正在处理的实施是IMO,这是对语言的滥用,但它恰好起作用。
澄清术语:
"Class
实例"是类方法中的self
+ (void)foo { self; }
实例方法中的"类的实例"是self
:
- (void)foo { self; }
在实践中,-[NSObject conformsToProtocol:]
是+[NSObject conformsToProtocol:]
,而+[NSObject class]
只是返回self
,所以在执行时没有错误。
那么,如果代码符合您描述的标准,我仍然不清楚为什么会收到警告。
我描述的标准适用于执行,但它偏离了语言的语义——因此,编译器在这方面是绝对正确的。
为了解决这个问题:没有办法告诉编译器"我的类实例符合协议",因为采用声明适用于类的实例。
您有两个主要选项:
干净、正确的方法:使用类的实例并按照定义实现协议。
或将类实例类型转换为协议:
id delegate=(id)self;fbSession=[fbSession sessionForApplication:SHKFacebookKeygetSessionProxy:SHKFacebookSessionProxyURLdelegate:delegate];
如果您选择#2,那么定义协议的实例方法以使用类方法可能会有所帮助,例如:
+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }
这也意味着你永远不需要实例。这将有所帮助,因为如果协议发生更改,它将添加警告。当您遵循约定时,这些警告会出现在类方法中。
为了减少噪音,您还可以考虑创建一些方法来将类型转换减少到一个位置:
+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return (id<SomeProtocol>)self;
}
- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return [[self class] sharedSomeProtocolDelegate];
}
然后你可以写:
fbSession = [FBSession sessionForApplication:SHKFacebookKey
getSessionProxy:SHKFacebookSessionProxyURL
delegate:[self sharedSomeProtocolDelegate]];
(注意,这些类型的实现实际上是类集群,您将在调试器中或打印时看到一些不同的东西)