1

例如,我有以下代码:

@interface LOSHeadlineMetricsService : NSObject {

    id<LOSHeadlineMetricsServiceDelegate>delegate;

}

协议看起来像

@protocol LOSHeadlineMetricsServiceDelegate <NSObject>

- (void) serviceDidComplete;

- (void) serviceFailed;

@end

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

if (self.delegate == nil) {
   [NSException raise:@"NOT IMPLEMENTED" format:@"%s", Reflection(self.delegate)]
}
4

2 回答 2

2

property_getAttributes()您可以从函数返回的属性属性中解析它。任何属性的类型都可以通过检查第一个字符(定义为 '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>)确实只是“@”,所以使用它需要您自担风险。当然,解析该字符串的任何代码都必须准备好优雅地失败,并且不依赖于关键任务数据提取。如果需要此信息更多是为了方便而不是硬必要,那么我认为这适合继续前进。

于 2013-03-28T22:49:38.543 回答
1

你不能。obj-c 对象的静态类型信息在编译过程中被丢弃。在运行时,您只知道它是一个 obj-c 对象(在这种情况下,“它”是一个属性/ivar)。


更新: Carl Veazey 的回答表明该信息确实存在于协议中。在测试之后,我看到了同样的事情。但是,这完全没有文档记录,我建议不要将其用于实际代码。

于 2013-03-28T22:14:02.443 回答