用于记录的运行时的协议名称

时间:2013-03-28 22:02:53

标签: objective-c cocoa-touch cocoa

我有以下代码,例如:

@interface LOSHeadlineMetricsService : NSObject {

    id<LOSHeadlineMetricsServiceDelegate>delegate;

}

@interface LOSHeadlineMetricsService : NSObject { id<LOSHeadlineMetricsServiceDelegate>delegate; }

,协议看起来像

在委托的客户端运行时,我想引发一个异常,它通过反射抛出协议“LOSHeadlineMetricsServiceDelegate”的名称。我怎样才能做到这一点?

@protocol LOSHeadlineMetricsServiceDelegate <NSObject>

- (void) serviceDidComplete;

- (void) serviceFailed;

@end

2 个答案:

答案 0 :(得分:2)

您可以从property_getAttributes()函数返回的属性属性中解析它。可以通过检查第一个字符(defined to be a 'T')和第一个逗号之间的文本来确定任何属性的类型。对于对象类型,此文本的格式为@“ClassName”。 id类型属性只有@符号,没有引号,类名或协议名称。你可以在这里相当有效地使用NSScanner,或者正则表达式,无论你喜欢什么。

示例程序及其输出:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@protocol MyProtocol <NSObject>
- (void)someMethod;
@end

@interface MyObject : NSObject
@property (strong) id<MyProtocol> implementor;
@end

@implementation MyObject
@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        objc_property_t property = class_getProperty([MyObject class], "implementor");
        const char *propertyAttributes = property_getAttributes(property);
        NSLog(@"property attributes = %s", propertyAttributes);
    }
    return 0;
}

该计划的输出是

  

2013-03-28 16:39:17.401 PropertyReflection[56502:303] property attributes = T@"<MyProtocol>",&,V_implementor

现在,正如Kevin Ballard指出的那样,谨慎地注意到这种行为与文档相矛盾,后者指出T之后的字符串是属性类型的@encode字符串。当我写这篇文章时,我认为是这样的。但是在检查之后,@encode(id<MyProtocol>)的结果确实只是“@”,因此使用此风险需要您自担风险。当然,解析该字符串的任何代码都必须准备好优雅地失败,而不是依赖于任务关键型数据提取。如果希望这些信息更像是为了方便而不是为了必要,那么我认为这是适合继续前进的。

答案 1 :(得分:1)

你做不到。在编译期间抛弃obj-c对象的静态类型信息。在运行时,你所知道的是它是一个obj-c对象(在这种情况下,“it”是一个属性/ ivar)。


更新:Carl Veazey的回答表明该信息确实存在于协议中。经过测试,我看到了同样的事情。但是,这完全没有记录,我建议不要依赖它来获取实际代码。