【发布时间】:2013-05-25 02:26:24
【问题描述】:
我正在尝试强制执行“正式”@protocol,但无法可靠地测试我的类/实例是否真正实现了协议的“必需”方法,而不是简单地“声明”它们符合协议。
我的困惑的一个完整的例子......
#import <Foundation/Foundation.h>
@protocol RequiredProtocol
@required
- (NSString*) mustImplement; @end
@interface Cog : NSObject <RequiredProtocol> @end
@implementation Cog @end
@interface Sprocket : NSObject @end
@implementation Sprocket
- (NSString*) mustImplement
{ return @"I conform, but ObjC doesn't care!"; } @end
int main(int argc, char *argv[]) {
Protocol *required = @protocol(RequiredProtocol);
SEL requiredSEL = @selector(mustImplement);
void (^testProtocolConformance)(NSObject*) = ^(NSObject *x){
NSLog(@"Protocol:%@\n"
"Does %@ class conform:%@ \n"
"Do instances conform:%@ \n"
"Required method's result:\"%@\"",
NSStringFromProtocol ( required ),
NSStringFromClass ( x.class ),
[x.class conformsToProtocol:required] ? @"YES" : @"NO",
[x conformsToProtocol:required] ? @"YES" : @"NO",
[x respondsToSelector:requiredSEL] ? [x mustImplement]
: nil );
};
testProtocolConformance ( Cog.new );
testProtocolConformance ( Sprocket.new );
}
结果:
Protocol:RequiredProtocol
Does Cog class conform:YES
Do instances conform:YES
Required method's result:"(null)"
Protocol:RequiredProtocol
Does Sprocket class conform:NO
Do instances conform:NO
Required method's result:"I conform, but ObjC doesn't care!"
为什么实现@protocol的方法(Sprocket)的类及其实例将NO返回到conformsToProtocol?
为什么一个实际上不符合,但说它确实(Cog)返回YES?
正式协议的意义何在?如果声明就是假装符合性所需要的全部内容?
如果没有多次调用respondsToSelector,您如何才能真正检查多个@selectors 的完整实现?
@Josh Caswell.. 如果没有diff这两个...
@implementation NSObject (ProtocolConformance)
- (BOOL) implementsProtocol:(id)nameOrProtocol {
Protocol *p = [nameOrProtocol isKindOfClass:NSString.class]
? NSProtocolFromString(nameOrProtocol)
: nameOrProtocol; // Arg is string OR protocol
Class klass = self.class;
unsigned int outCount = 0;
struct objc_method_description *methods = NULL;
methods = protocol_copyMethodDescriptionList( p, YES, YES, &outCount);
for (unsigned int i = 0; i < outCount; ++i) {
SEL selector = methods[i].name;
if (![klass instancesRespondToSelector: selector]) {
if (methods) free(methods); methods = NULL; return NO;
}
}
if (methods) free(methods); methods = NULL; return YES;
}
@end
【问题讨论】:
-
如果一个类没有实现需要的方法,你会得到一个警告……这是一个编程错误;
-
那是一些彻头彻尾的时髦代码格式......
-
tl;dr 编译器检查协议一致性。采取零警告/错误策略,您就会知道这些类符合协议。在运行时检查将是多余的,可能很慢,并且运行时间不可预测。
-
@bbum 格式有点做作 - 消除“滚动”,也就是切断我。 @Grady Player 谢谢!我以为我要疯了……但你的强调让我看起来 - 并意识到 - 我已将
-w插入到我的Code Runner编译脚本中。呵呵。
标签: objective-c class methods protocols