我正在尝试执行“正式的”@protocol
,但无法可靠地测试我的类/实例是否确实实现了协议(protocol)的“必需”方法,而不是简单地“声明”他们符合协议(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
?
如果只需要声明就可以假装符合,那么正式协议(protocol)还有什么意义呢?
如何在不多次调用 respondsToSelector
的情况下实际检查多个 @selector
的完整实现?
@Josh Caswell.. 没有 diff
两者.. 我猜你的响应达到了与我一直在使用的 NSObject
上的类别相似的效果同时……
@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
最佳答案
遵守协议(protocol)只是一个“ promise ”,您无法知道conformsToProtocol: 的接收者是否真的实现了所有需要的方法。使用尖括号语法声明该类符合协议(protocol)就足够了,conformsToProtocol: 将返回 yes:
Discussion
A class is said to “conform to” a protocol if it adopts the protocol or inherits from another class that adopts it. Protocols are adopted by listing them within angle brackets after the interface declaration.
完整来源:NSObject's conformsToProtocol: .
协议(protocol)声明的优势在于您可以在编译时知道一个类是否真的采用了所需的方法。如果没有,将发出警告。我建议不要依赖conformsToProtocol:,而是使用内省(introspection)。也就是说,通过调用 instancesRespondToSelector:/respondsToSelector: 来验证一个类/对象是否实现了一个方法:
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
- (BOOL)respondsToSelector:(SEL)aSelector;
关于objective-c - 为什么 "conformsToProtocol"不检查 "required"方法实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16820466/