Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Objective-C have an equivalent to java annotations?

Does Objective-C have an equivalent to java annotations?

What's I'm trying to do is create a property and be able to somehow access some metadata about it.

I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.

//Put some sort of annotation giving a class name.
@property (strong) NSArray *myArray;
like image 950
Rocky Pulley Avatar asked Dec 06 '12 20:12

Rocky Pulley


2 Answers

There is no native support of this functionality, but you may to take a look at following solution — https://github.com/epam/lib-obj-c-attr/ It is compile time implementation of attributes. Definition of attributes based on defines but not on comments as in other solutions like ObjectiveCAnnotate.

like image 26
Nikita Leonov Avatar answered Sep 30 '22 16:09

Nikita Leonov


You said:

I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.

There are a few ways to do this sort of thing in Objective-C. Apple's frameworks do this sort of thing by adding a class method that returns the required information. Examples: dependent keys in KVO, +[CALayer needsDisplayForKey:] and related methods.

So, let's create a class method that returns an array of classes that can go into your container property, given the property name. First, we'll add a category to NSObject to implement a generic version of the method:

@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

As you can see, this default version of the method doesn't do anything particularly useful. But adding it to NSObject means we can send the message to any class without worrying about whether that class implements the method.

To make the message return something useful, we override it in our own classes. For example:

@implementation MyViewController

+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
    if ([name isEqualToString:@"myArray"]) {
        return @[ [UIButton class], [UIImageView class] ];
    } else {
        return [super allowedClassesForContainerPropertyWithName:name];
    }
}

...

We can use it like this:

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
}
like image 57
rob mayoff Avatar answered Sep 30 '22 15:09

rob mayoff