在类中使用self方法

Jim*_*Jim 9 class-design objective-c class-method objc-protocol

我在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];
}
Run Code Online (Sandbox Code Playgroud)

jus*_*tin 14

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

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

+ (id)new
{
  return [[self alloc] init];
}
Run Code Online (Sandbox Code Playgroud)

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

前:

NSArray * a = [NSArray new]; // << a is an NSArray
Run Code Online (Sandbox Code Playgroud)

ex b:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray
Run Code Online (Sandbox Code Playgroud)

见下面的注释.

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

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

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

澄清术语:

" Class实例"是self一个类方法:

+ (void)foo { self; }
Run Code Online (Sandbox Code Playgroud)

"类self的实例" 在实例方法中:

- (void)foo { self; }
Run Code Online (Sandbox Code Playgroud)

在实践中,-[NSObject conformsToProtocol:]is +[NSObject conformsToProtocol:]+[NSObject class]just返回self所以执行时没有错误.

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

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

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

您有两个主要选择:

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

  2. 或Typecast协议的类实例:

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

如果选择#2,则可以帮助定义协议的实例方法以使用类方法,如下所示:

+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }
Run Code Online (Sandbox Code Playgroud)

这也意味着你永远不需要实例.它会有所帮助,因为如果协议发生变化,它会添加警告.遵循约定时,这些警告会冒泡到类方法.

为了减少噪音,您还可以考虑创建一些方法来将类型转换减少到一个位置:

+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return (id<SomeProtocol>)self;
}

- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return [[self class] sharedSomeProtocolDelegate];
}
Run Code Online (Sandbox Code Playgroud)

然后你可以写:

fbSession = [FBSession sessionForApplication:SHKFacebookKey
                             getSessionProxy:SHKFacebookSessionProxyURL
                                    delegate:[self sharedSomeProtocolDelegate]];
Run Code Online (Sandbox Code Playgroud)

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