9

我在 ShareKit 中遇到了这段代码,我不明白作者在想什么,self在类方法中使用。有一个警告:不兼容的指针类型将“类”发送到参数类型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];
}
4

1 回答 1

14

self可以在类方法中用作多态类实例。

因此,类方法new可以这样实现:

+ (id)new
{
  return [[self alloc] init];
}

并将返回消息传递的 Class 实例的正确类型:

例如:

NSArray * a = [NSArray new]; // << a is an NSArray

例如:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray

请参阅下面的注释。

所以你真正面临的是确保协议中只有实例方法,并且(类)自身的方法映射出来采用协议中的实例方法。

至于设计......好吧,让我们说我不会这样写。单身人士会更清晰,更正确,但我什至不喜欢单身人士,所以我不会走那条路。

产生警告是因为Class实例(传递的内容)确实采用了参数@protocol指定的值delegate。该Class实例不是该类的实例。协议声明确实适用于类的实例。例如,如果您采用NSLocking,编译器是否希望您也为协议中声明的每个实例方法实现类方法?答:从来没有。您正在处理的实现是 IMO 滥用该语言的情况之一,但它恰好可以工作。

为了澄清术语:

Class实例”self在类方法中:

+ (void)foo { self; }

“类的实例”self在实例方法中:

- (void)foo { self; }

在实践中,-[NSObject conformsToProtocol:]is+[NSObject conformsToProtocol:]并且+[NSObject class]只是返回self,因此执行时没有错误。

那么,如果代码符合您描述的标准,我仍然不清楚为什么我会收到警告。

我描述的标准适用于执行,但它偏离了语言的语义——因此,编译器在这方面是绝对正确的。

为了解决这个问题:没有办法告诉编译器“我的类实例符合协议”,因为采用声明适用于类的实例

您有两个主要选择:

  1. 干净、正确的方法:使用类的实例并按照定义实现协议。

  2. 或将类实例类型转换为协议:

    id 委托 = (id)self; fbSession = [FBSession sessionForApplication:SHKFacebookKey getSessionProxy:SHKFacebookSessionProxyURL delegate: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]];

(注意这些类型的实现实际上是类簇,你会在调试器中看到不同的东西,或者如果打印出来)

于 2012-01-27T03:39:19.067 回答