为什么"conformsToProtocol"不检查"必需"方法实现?

Ale*_*ray 5 methods protocols class objective-c

我试图强制执行"正式" @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 );
}
Run Code Online (Sandbox Code Playgroud)

结果:

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!"
Run Code Online (Sandbox Code Playgroud)

为什么是它一个类,它是国家执行情况@protocol的方法(Sprocket)返回NOconformsToProtocol

为什么一个实际上并不符合规定,但是它确实会Cog回归YES

什么是点正式协议,如果该声明是所有的需要假装一致性?

如果@selector没有MULTIPLE调用,你如何才能实际检查多个s的完整实现respondsToSelector

@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
Run Code Online (Sandbox Code Playgroud)

Ram*_*uri 9

符合协议只是一个"承诺",你可以不知道如果接收机conformsToProtocol:实际上实现了所有必需的方法.足以让您使用尖括号语法声明该类符合协议,并且conformsToProtocol:将返回yes:

讨论
如果一个类采用协议或从另一个采用它的类继承,则称该类符合协议.通过在接口声明后将它们放在尖括号内来采用协议.

完整来源:NSObject的conformsToProtocol : .

协议声明的优势在于,您可以在编译时知道类是否真正采用了所需的方法.如果没有,将发出警告.我建议不要依赖conformsToProtocol : ,而是使用内省代替.也就是说,验证类/对象是否通过调用instancesRespondToSelector实现方法:/respondsToSelector ::

+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
- (BOOL)respondsToSelector:(SEL)aSelector;
Run Code Online (Sandbox Code Playgroud)