Имеет ли Objective-C эквивалент аннотации java?

Имеет ли Objective-C эквивалент аннотации java?

То, что я пытаюсь сделать, это создать свойство и иметь возможность каким-то образом получить доступ к некоторым метаданным.

Я хочу, чтобы определить, какие типы классов должны входить в мой массив, поэтому я хотел бы как-то его аннотировать. Затем вы сможете получить доступ к этой аннотации через нечто вроде библиотеки времени выполнения, где я могу получить доступ к спискам свойств и их имен.

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

Ответ 1

Ты сказал:

Я хочу, чтобы определить, какие типы классов должны входить в мой массив, поэтому я хотел бы как-то его аннотировать. Затем вы сможете получить доступ к этой аннотации через нечто вроде библиотеки времени выполнения, где я могу получить доступ к спискам свойств и их имен.

Есть несколько способов сделать такие вещи в Objective-C. Рамки Apple делают такие вещи, добавляя метод класса, который возвращает требуемую информацию. Примеры: зависимые ключи в +[CALayer needsDisplayForKey:], +[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
}

Ответ 2

Не существует встроенной поддержки этой функции, но вы можете взглянуть на следующее решение: https://github.com/epam/lib-obj-c-attr/. Это реализация атрибутов времени компиляции. Определение атрибутов, основанных на определениях, но не на комментариях, как в других решениях, таких как ObjectiveCAnnotate.

Ответ 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 
    }
}

Ответ 4

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 

Конечно, есть некоторые ограничения. Поскольку вы создали свою собственную категорию, вы должны использовать свой собственный метод для инициализации и создания собственного массива.

Ответ 5

Имеет ли 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).

Если вы специально хотите хранить пользовательские метаданные об объекте или классе, вы можете сделать это с помощью связанных ссылок.

Ответ 6

Я ожидаю, что теперь это будет ясно, ответ НЕТ, а не сейчас.

Некоторые люди нашли некоторые альтернативы, которые, похоже, работают в конкретных случаях их использования.

Но в целом нет объективной сопоставимой функции в объективе-с. Метаданные IMHO clang, похоже, являются хорошей основой для этого, но пока Apple не поддерживает Apple, это не поможет, насколько я понял.

Btw. Я думаю, это должно быть ясно, но просто для повторения для всех: для поддержки аннотаций, предусмотренных в java, требуется два изменения.

  1. Языку требуется расширение аннотации, например, методы, свойства, классы,... в исходном коде.
  2. Для доступа к аннотированной информации требуется стандартный интерфейс. Это может обеспечить только яблоко.

Большинство альтернативных сигналов перемещают информацию аннотации во время выполнения и определяют их собственный интерфейс. Среда выполнения-c обеспечивает стандартный интерфейс, но только с некоторым трюком вы можете аннотировать свойства и все же isse среды выполнения.

Типичным примером использования для функции является контейнер IOC (например, Java), который использует аннотированную информацию для ввода других объектов.

Я бы предложил открыть для Apple поддержку, чтобы поддержать это.

Ответ 7

Ответ на ваш вопрос заключается в том, что Objective-C не имеет прямого эквивалента аннотаций, найденных в Java/С#, и хотя некоторые из них предположили, что вы могли бы что-то спроектировать по тем же линиям, вероятно, это слишком много работы или не пройдет.

Чтобы ответить на вашу конкретную потребность, см. Этот ответ, который показывает, как построить массив, содержащий объекты только одного типа; принудительное выполнение является динамическим, а не статичным, как с параметрическими типами/дженериками, но это то, что вы получите с помощью аннотации, поэтому оно, вероятно, соответствует вашей конкретной потребности в этом случае. НТН.

Ответ 8

Что вам нужно, может быть, парсер метаданных для Objective-C. Я использовал ObjectiveCAnnotate (время восстановления компиляции) и ROAnnotation (время выполнения можно восстановить).