Rocky Pulley
Rocky Pulley

Reputation: 23301

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;

Upvotes: 12

Views: 10239

Answers (8)

Stephan
Stephan

Reputation: 4263

I expect it should be clear now, the answer is NO, not at the moment.

Some people found some alternatives which seem to work in their specific use cases.

But in general there is no comparable feature yet in objective-c. IMHO clang metadata seems to provide a good foundations for this, but as long as there is not support from Apple this will not help, as far as i understood it.

Btw. I guess it should be clear, but just to repeat for all: two changes are required to support annotations as provided in java.

  1. The language need an extension the annotate e.g. methodes, properites, classes, ... in the source code.
  2. A standard interface is required to access the annotated information. This can only provide by apple.

Most alternativ soltuions move the annotation information into runtime and define their own interface. The objective-c runtime provide a standard interface but only with some trick you can annotate properties and still the isse of runtime population.

The typical use case for suche a feature is an IOC container (in Java e.g. Spring) which use the annotated information to inject other objects.

I would suggest to open an feature requrest for Apple to support this.

Upvotes: 1

Nikita Leonov
Nikita Leonov

Reputation: 5694

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.

Upvotes: 5

Jibeex
Jibeex

Reputation: 5819

What you need maybe a metadata parser for Objective-C. I have used ObjectiveCAnnotate (compile time retrievable) and ROAnnotation(runtime retrievable).

Upvotes: 0

Jano
Jano

Reputation: 63667

No, Objective-C has no annotation or generics support.


A way to implement such a thing would be to hack Clang to read comments and associate a metadata object to the original object. But, you would be tied to your hacked compiler.

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);

Qualifying with a protocol wouldn't be much trouble, and you could test if the collection implements it, but along the way you would need to create a category for each type on the same collection. This would require a different collection at compile time using macros. Overly complicated.

@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 
    }
}

Upvotes: 3

rob mayoff
rob mayoff

Reputation: 385680

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
}

Upvotes: 9

CRD
CRD

Reputation: 53000

The answer to your question is that Objective-C does not have a direct equivalent of annotations as found in Java/C#, and though as some have suggested you might be able to engineer something along the same lines it probably is either far too much work or won't pass muster.

To address your particular need see this answer which shows how to construct an array which holds objects of only one type; enforcement is dynamic and not static as with parametric types/generics, but that is what you'd be getting with your annotation so it probably matches your particular need in this case. HTH.

Upvotes: 0

Sandeep
Sandeep

Reputation: 21144

Objective C does not support generics like in Java but ofcourse the language is very flexible that you can accomplish almost anything with simple tricks and knowledge. To implement a generic like feature you could create a category on NSArray class and create your own method to initialize the array and then check to see if the object is really the type of the object you want.

I would write a simple category on NSArray to have such functionality. Say suppose, I want my array to hold objects of class MyClass only then my category would look like,

@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 

Of course, there is some limitations to it. Since you have created your own category, you should use your own method to initialize and create your own array.

Upvotes: 3

user529758
user529758

Reputation:

Does Objective-C have an equivalent to java annotations?

Not exactly an equivalent, but there is, and it's better. In Objective-C, the compiler has to store some type and name information in the compiled code (because the language is highly dynamic, a lot of things happen at runtime as opposed to compile time), for example method names ("selectors"), method type signatures, data about properties, protocols, etc. The Objective-C runtime library then has access to this data. For example, you can get the list of properties an object has by writing

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

Or you can check what class an object belongs to:

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

(Yes, part of the runtime library is itself wrapped into some methods of NSObject for convenience, others only have C function APIs.)

If you specifically want to store custom metadata about an object or a class, you can do that using associated references.

Upvotes: 2

Related Questions