你说:
我希望能够确定我的数组中应该包含什么类型的类,所以我想以某种方式对其进行注释。然后以后可以通过运行时库之类的东西访问该注释,我可以在其中访问属性列表及其名称。
在 Objective-C 中有几种方法可以做这种事情。 Apple 的框架通过添加返回所需信息的类方法来执行此类操作。示例:dependent keys in KVO、+[CALayer needsDisplayForKey:] and related methods。
因此,让我们创建一个类方法,该方法返回一个类数组,这些类可以在给定属性名称的情况下进入您的容器属性。首先,我们将向NSObject 添加一个类别来实现该方法的通用版本:
@interface NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name;
@end
@implementation NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if (class_getProperty(self, name.UTF8String)) {
return @[ [NSObject class] ];
} else {
[NSException raise:NSInvalidArgumentException
format:@"%s called for non-existent property %@", __func__, name];
abort();
}
}
@end
如您所见,该方法的默认版本并没有做任何特别有用的事情。但是将它添加到NSObject 意味着我们可以将消息发送到任何类,而不必担心该类是否实现了该方法。
为了使消息返回有用的信息,我们在自己的类中覆盖它。例如:
@implementation MyViewController
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if ([name isEqualToString:@"myArray"]) {
return @[ [UIButton class], [UIImageView class] ];
} else {
return [super allowedClassesForContainerPropertyWithName:name];
}
}
...
我们可以这样使用它:
SomeViewController *vc = ...;
SomeObject *object = ...;
if ([[vc.class allowedClassesForContainerPropertyWithName:@"bucket"] containsObject:object.class]) {
[vc.bucket addObject:object];
} else {
// oops, not supposed to put object in vc.bucket
}