あなたが言った:
配列に含めるクラスのタイプを決定できるようにしたいので、なんとかして注釈を付けたいと思います。その後、プロパティとその名前のリストにアクセスできるランタイムライブラリなどを介してそのアノテーションにアクセスできるようになります。
Objective-Cでこの種のことを行うにはいくつかの方法があります。Appleのフレームワークは、必要な情報を返すクラスメソッドを追加することにより、この種のことを行います。例:KVOの依存キー、+[CALayer needsDisplayForKey:]
および関連するメソッド。
それでは、プロパティ名を指定して、コンテナプロパティに入ることができるクラスの配列を返すクラスメソッドを作成しましょう。まず、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
}