12

Objective-CにはJavaアノテーションと同等のものがありますか?

私がやろうとしているのは、プロパティを作成し、それに関するメタデータに何らかの方法でアクセスできるようにすることです。

配列に含めるクラスのタイプを決定できるようにしたいので、なんとかして注釈を付けたいと思います。その後、プロパティとその名前のリストにアクセスできるランタイムライブラリなどを介してそのアノテーションにアクセスできるようになります。

//Put some sort of annotation giving a class name.
@property (strong) NSArray *myArray;
4

8 に答える 8

9

あなたが言った:

配列に含めるクラスのタイプを決定できるようにしたいので、なんとかして注釈を付けたいと思います。その後、プロパティとその名前のリストにアクセスできるランタイムライブラリなどを介してそのアノテーションにアクセスできるようになります。

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
}
于 2012-12-06T22:00:09.110 に答える
5

この機能のネイティブサポートはありませんが、次の解決策を検討することをお勧めします— <a href="https://github.com/epam/lib-obj-c-attr/" rel="noreferrer"> https://github.com/epam/lib-obj-c-attr/これはコンパイル時の属性の実装です。ObjectiveCAnnotateのような他のソリューションのように、コメントではなく定義に基づく属性の定義。

于 2014-03-25T22:38:04.663 に答える
3

いいえ、Objective-Cにはアノテーションやジェネリックスのサポートはありません。


このようなことを実装する方法は、Clangをハックしてコメントを読み取り、メタデータオブジェクトを元のオブジェクトに関連付けることです。しかし、あなたはハッキングされたコンパイラに縛られるでしょう。

NSString *v1 = [[NSString alloc] init];

// associate
static char key;
NSString *v2 = [[NSString alloc] init];
objc_setAssociatedObject (
    v1,
    &key,
    v2,
    OBJC_ASSOCIATION_RETAIN
);

// retrieve
NSString *associate = (NSString *)objc_getAssociatedObject(v1, &key);

プロトコルでの認定はそれほど問題にはならず、コレクションがそれを実装しているかどうかをテストできますが、その過程で、同じコレクションに各タイプのカテゴリを作成する必要があります。これには、マクロを使用したコンパイル時に別のコレクションが必要になります。過度に複雑。

@interface Tomato:NSObject @end
@implementation Tomato @end

@protocol TomatoNSArray <NSObject>
- (Tomato*)objectAtIndexedSubscript:(NSUInteger)index;
- (void)setObject:(Tomato*)tomato atIndexedSubscript:(NSUInteger)index;
@end

// here is the problem, you would need to create one of this for each type
@interface NSMutableArray (TomatoNSArray) <TomatoNSArray>
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        NSMutableArray<TomatoNSArray> *tomatoes = [[NSMutableArray alloc] initWithCapacity:2];
        tomatoes[0] = [Tomato new];
        tomatoes[1] = [NSObject new]; // warning: incompatible pointer types 
    }
}
于 2012-12-06T21:18:52.203 に答える
3

Objective CはJavaのようなジェネリックスをサポートしていませんが、もちろん言語は非常に柔軟なので、簡単なトリックと知識でほとんど何でも達成できます。ジェネリックのような機能を実装するには、NSArrayクラスにカテゴリを作成し、独自のメソッドを作成して配列を初期化し、オブジェクトが本当に必要なオブジェクトのタイプであるかどうかを確認します。

そのような機能を持つために、NSArrayに簡単なカテゴリを記述します。たとえば、配列にクラスMyClassのオブジェクトのみを保持させたい場合、カテゴリは次のようになります。

@interface NSArray(MyCategory)

@end

@implementation NSArray(MyCategory)

-(NSArray*)arrayWithMyClasses:(NSArray*)classes{
    if([classes count] > 0){
        NSMutableArray *array = [[NSMutableArray alloc] init];
        for(id anObj in classes){
            NSAssert([anObj isKindOfClass:[MyClass class]], @"My array supports only objetcts of type MyClass");
            [array addObject:anObj];
        }
        return array;
    }
    return nil;
}
@end 

もちろん、それにはいくつかの制限があります。独自のカテゴリを作成したので、独自のメソッドを使用して独自の配列を初期化および作成する必要があります。

于 2012-12-06T21:36:47.077 に答える
2

Objective-CにはJavaアノテーションと同等のものがありますか?

完全に同等ではありませんが、あり、それはより良いです。Objective-Cでは、コンパイラはコンパイルされたコードに型と名前の情報を格納する必要があります(言語は非常に動的であるため、コンパイル時ではなく実行時に多くのことが発生します)。たとえば、メソッド名(「セレクタ」) 、メソッドタイプの署名、プロパティ、プロトコルなどに関するデータ。Objective-Cランタイムライブラリは、このデータにアクセスできます。たとえば、オブジェクトが持つプロパティのリストを取得するには、次のように記述します。

id object = // obtain an object somehow
unsigned count;
objc_property_t *props = class_copyPropertyList([object class], &count);

または、オブジェクトがどのクラスに属しているかを確認できます。

if ([object isKindOfClass:[NSArray class]]) {
    // do stuff
}

(はい、ランタイムライブラリの一部は、便宜上NSObjectの一部のメソッドにラップされていますが、他のメソッドにはC関数APIしかありません。)

オブジェクトまたはクラスに関するカスタムメタデータを具体的に保存する場合は、関連する参照を使用して保存できます。

于 2012-12-06T20:40:44.370 に答える
1

今ははっきりしているはずですが、答えはNOであり、現時点ではありません。

一部の人々は、特定のユースケースで機能すると思われるいくつかの代替案を見つけました。

しかし、一般的に、Objective-cにはまだ同等の機能はありません。IMHO clangメタデータは、これに対する優れた基盤を提供しているようですが、Appleからのサポートがない限り、私が理解している限り、これは役に立ちません。

ところで。明確なはずですが、すべてを繰り返すだけです。Javaで提供されているアノテーションをサポートするには、2つの変更が必要です。

  1. 言語には、ソースコード内のメソッド、プロパティ、クラスなどに注釈を付ける拡張機能が必要です。
  2. 注釈付き情報にアクセスするには、標準のインターフェースが必要です。これはアップルによってのみ提供できます。

ほとんどの代替ソリューションは、注釈情報をランタイムに移動し、独自のインターフェースを定義します。Objective-cランタイムは標準のインターフェースを提供しますが、いくつかのトリックを使用するだけで、プロパティに注釈を付けることができ、それでもランタイムの数が多くなります。

このような機能の一般的な使用例は、注釈付きの情報を使用して他のオブジェクトを挿入するIOCコンテナ(JavaなどのSpring)です。

これをサポートするために、Appleに必要な機能を開くことをお勧めします。

于 2014-05-21T06:37:47.750 に答える
0

あなたの質問への答えは、Objective-CにはJava / C#に見られるようなアノテーションに直接相当するものがないということです。またはマスターを通過しません。

特定のニーズに対応するには、1つのタイプのみのオブジェクトを保持する配列を作成する方法を示すこの回答を参照してください。強制は動的であり、パラメトリックタイプ/ジェネリックのように静的ではありませんが、それがアノテーションで得られるものであるため、この場合の特定のニーズにおそらく一致します。HTH。

于 2012-12-06T21:47:24.540 に答える
0

必要なのは、Objective-Cのメタデータパーサーかもしれません。ObjectiveCAnnotate(コンパイル時の取得可能)とROAnnotation(実行時の取得可能)を使用しました。

于 2014-02-26T16:33:13.097 に答える