在类中使用self方法

时间:2012-01-27 03:14:57

标签: objective-c class-design class-method objc-protocol

我在ShareKit中遇到过这段代码,在类方法中使用self时,我不明白作者的想法。有一个警告:不兼容的指针类型发送&#39; Class&#39;到参数类型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];
}

1 个答案:

答案 0 :(得分:14)

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

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

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

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

ex a:

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

ex b:

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

见下面的注释。

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

就设计而言......好吧,我只想说我不会这样写。单身人士会更清楚,更正确,但我不喜欢单身人士,所以我不会采取这种方式。

产生警告是因为 Class 实例(传递的内容)确实采用@protocol参数指定的delegateClass实例不是该类的实例。协议声明确实适用于该类的实例。例如,如果采用NSLocking,编译器是否期望您还为协议中声明的每个实例方法实现类方法?答:永远不会。您正在处理的实施是IMO其中一种滥用该语言的情况,但它恰好起作用。

澄清术语:

&#34; Class实例&#34;在类方法中是self

+ (void)foo { self; }

&#34;班级的实例&#34;在实例方法中是self

- (void)foo { self; }

实际上,-[NSObject conformsToProtocol:]+[NSObject conformsToProtocol:]+[NSObject class]只返回self,因此执行时没有错误。

  

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

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

要解决问题:没有办法告诉编译器&#34;我的类实例符合协议&#34;因为采用声明适用于类的实例

您有两个主要选项:

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

  2. 或者对协议的类实例进行Typecast:

    id delegate =(id)self; fbSession = [FBSession sessionForApplication:SHKFacebookKey                              getSessionProxy:SHKFacebookSessionProxyURL                                     委托:委托];

  3. 如果选择#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]];
    

    (请注意,这些类型的实现实际上是类集群,您将在调试器中看到不同的内容或打印出来的内容)