12

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;
Rocky Pulley
  • 22,531
  • 20
  • 68
  • 106
  • Comments. And there are a number of 3rd party packages (including possibly JavaDoc) that will extract specially-formatted comments and turn them into documents. – Hot Licks Dec 06 '12 at 20:27
  • So do you want to use reflection? –  Dec 06 '12 at 20:27
  • @Hot Licks an annotation is by definition a comment, but he's asking for actual compilation support that converts the annotation into functional runtime code – gview Dec 06 '12 at 20:28
  • yes it needs runtime support, not just a comment. – Rocky Pulley Dec 06 '12 at 20:30
  • There certainly are reflection-like facilities in Objective-C -- you can materialize the methods and instance variables, even add new ones. But these facilities won't materialize comments. – Hot Licks Dec 06 '12 at 20:35
  • 1
    This sounds more like Java generics rather than annotations. – grahamparks Dec 06 '12 at 20:39

8 Answers8

9

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
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
5

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.

Nikita Leonov
  • 5,684
  • 31
  • 37
3

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 
    }
}
Jano
  • 62,815
  • 21
  • 164
  • 192
3

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.

Sandeep
  • 20,908
  • 7
  • 66
  • 106
  • isKindOfClass violates general principal of generics :) – NinjaCoder Feb 04 '15 at 14:41
  • Well, you know objective c does not have generics by itself. So, to add features like so, either you would have to go through run time or do some monkey matching on the language itself. – Sandeep Feb 04 '15 at 14:49
2

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.

  • Until the last paragraph this doesn't address the question, and describes stuff Java does as well - so it's questionable whether "it's better" as those things. Coming to associated references, how do you add those to a property as compile time annotations? – CRD Dec 06 '12 at 21:41
  • @CRD everything you write in the code is compile-time... Isn't `objc_setAssociatedObject(object, @"This is a comment");` good enough for you? –  Dec 06 '12 at 21:53
  • 4
    I think you probably jest a little, there is clearly a difference between compile and runtime. It might be a fine point, but in Java/C# the annotation is pre-compiled metadata which is attached to the metadata of the property. `objc_setAssociatedObject(object, @"This is a comment")` is a statement which will be executed at runtime and will create an associated object per instance of the property. So the mechanisms are *different*, and they each have their pros'n'cons depending on the scenario. – CRD Dec 06 '12 at 22:06
  • My apologies for upsetting you, but one comment followed by a response to your question is hardly "badgering". Personally I think one piece of metadata vs. one associated object per property instance is something some folks might care about, but some of course will not. Have a nice day. – CRD Dec 06 '12 at 22:14
  • @CRD i agree with you. this it totally different and doesnt even touch annotations. I didnt downvote it but I would very much if this was edited. -- it answers the question – Daij-Djan Dec 07 '12 at 01:25
  • @H2CO3 java annotations would be more like clang metadata.. which I would love to use myself.. but dont know how it works :) – Daij-Djan Dec 07 '12 at 01:28
1

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.

Stephan
  • 4,263
  • 2
  • 24
  • 33
0

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.

Community
  • 1
  • 1
CRD
  • 52,522
  • 5
  • 70
  • 86
0

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

Jibeex
  • 5,509
  • 3
  • 27
  • 37