如何将 Class 对象转换为符合协议
Posted
技术标签:
【中文标题】如何将 Class 对象转换为符合协议【英文标题】:How to cast Class object to conformance witih protocol 【发布时间】:2012-12-29 01:52:48 【问题描述】:我正在尝试将 Class 对象强制转换为某个协议,该协议定义了该类实现的类方法 (+)。
如in this question 所述,我知道如何使用 (id
基本场景如下。
我有一个协议:
@protocol Protocol <NSObject>
+ (id)classMethod:(id)arg;
@end
然后我有一个函数,它接受一个 Class 对象,它知道它有时符合基于另一个参数的协议(这显然非常简化):
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
id instance;
if (arg != nil)
instance = [(Class<Protocol>)cls classMethod:arg];
现在我没有收到任何警告,我觉得它是正确的。 (在任何情况下我都不会看到任何错误,因为我可以保证如果 arg != nil 则该类符合。)
但是,我没有在 Xcode 中获得自动完成功能,这让我想知道这是否是正确的方法。有什么想法吗? (请注意,我对实例是 id
【问题讨论】:
与其将其转换为协议,不如更改类本身,使其符合该协议(例如 .h 中的@interface MyClass <MyProtocol>
或 .m 中的 @interface MyClass () <MyProtocol>
。然后编译器将允许使用该协议的方法自动完成并且不需要强制转换。修复对象或类定义通常比强制转换更好。此外,通过定义类以符合特定协议,编译器也会发出警告如果您未能实现协议的某些必需方法。
谢谢,但也许我不够清楚。 cls 是一个类对象(Class 类型的对象),而不是我定义的类(换句话说,它作为 [SomeClass 类] 传入)。在这个简单的例子中,如果 arg != nil,那么我知道 cls 是一个实现协议的类。我只是想让 Xcode 意识到这一点。
我很惊讶您在这里没有收到编译器警告,因为首先您将 BOOL 与指针进行比较(传递 nil
的 arg
与传递 @ 相同987654328@),其次你没有从这个方法返回任何东西。也许您使用的是不生成警告的旧版本的编译器,或者您可能关闭了一些警告。如果arg
是id
或指针,则您的构造是有意义的,但如果BOOL
则不是。此外,您不会返回instance
。当我编译你的代码时,我会收到这两个警告。
该代码显然不是整个函数,它只是前几行。 arg 本来是 id,但我错误地复制了它。我唯一担心的是班级演员表。
【参考方案1】:
如果您想确定cls
是否符合特定协议(并假设classMethod:
是该协议的必需类方法),您可以简单地:
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
id instance;
if ([cls conformsToProtocol:@protocol(Protocol)])
instance = [cls classMethod:arg];
return instance;
或者,只看它是否响应特定的类方法选择器:
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
id instance;
if ([cls respondsToSelector:@selector(classMethod:)])
instance = [cls classMethod:arg];
return instance;
【讨论】:
嗨 Rob,我知道 cls 已经符合给定的协议(这是函数的先决条件,如果 arg 不为零,则 cls 将符合)。我所追求的是一种让阅读我的代码没有明确测试一致性的人清楚这一点的方法(如我上面链接的问题)。我真的很好奇 ClassClass<Protocol>
是有效的,尽管没有必要且不典型。但是如果你想执行这个转换,这个语法是合适的。
顺便说一句,您提到的问题确实明确测试一致性(这是好的,防御性编程),并且仅将指针转换为协议只是为了防止编译器警告。恕我直言,这两个条件在这里都不成立。您要求未来的开发人员查看实现的细节以推断应该传递什么类,但是您不能优雅地处理他们意外传递错误类的情况。我会支持conformsToProtocol
或respondsToSelector
(无论是与你的演员一起还是代替)。
恕我直言,我将不得不不同意这一点。如果我为函数指定前提条件,那么我不会在运行时测试它(断言除外)。如果不满足先决条件,此功能或应用程序将无能为力,因此协议检查的开销没有用处。
@sapi 够公平的。我们会同意不同意这一点。 :)以上是关于如何将 Class 对象转换为符合协议的主要内容,如果未能解决你的问题,请参考以下文章