Objective-C是否具有与java注释相同的功能?

时间:2012-12-06 20:23:35

标签: objective-c ios

Objective-C是否具有与java注释等效的内容?

我要做的是创建一个属性,并能够以某种方式访问​​有关它的一些元数据。

我希望能够确定应该在我的数组中使用哪种类型的类,因此我想以某种方式对其进行注释。然后可以通过类似运行时库的东西访问该注释,我可以在其中访问属性列表及其名称。

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

7 个答案:

答案 0 :(得分:9)

你说:

  

我希望能够确定应该在我的数组中使用哪种类型的类,因此我想以某种方式对其进行注释。然后可以通过类似运行时库的东西访问该注释,我可以在其中访问属性列表及其名称。

在Objective-C中有几种方法可以做这种事情。 Apple的框架通过添加返回所需信息的类方法来完成此类操作。示例:dependent keys in KVO+[CALayer needsDisplayForKey:] and related methods

因此,让我们创建一个类方法,该方法返回一个类数组,这些类可以在给定属性名称的情况下进入容器属性。首先,我们将向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
}

答案 1 :(得分:5)

此功能没有本机支持,但您可以查看以下解决方案 - https://github.com/epam/lib-obj-c-attr/这是属性的编译时实现。基于定义而非注释的属性定义,如在其他解决方案中,如ObjectiveCAnnotate。

答案 2 :(得分: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 

当然,它有一些限制。由于您已创建自己的类别,因此应使用自己的方法初始化并创建自己的数组。

答案 3 :(得分:2)

  

Objective-C是否具有与java注释等效的内容?

不完全相同,但有,并且它更好。在Objective-C中,编译器必须在编译的代码中存储一些类型和名称信息(因为语言是高度动态的,很多事情发生在运行时而不是编译时),例如方法名称(“选择器”) ,方法类型签名,有关属性,协议等的数据。Objective-C runtime library然后可以访问此数据。例如,您可以通过编写

来获取对象具有的属性列表
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。)

如果您特别想要存储有关对象或类的自定义元数据,可以使用associated references.

执行此操作

答案 4 :(得分:1)

我希望现在应该清楚,答案是,而不是现在。

有些人发现了一些似乎适用于特定用例的替代方案。

但总的来说,目标c中还没有类似的功能。 IMHO clang元数据似乎为此提供了良好的基础,但只要没有Apple的支持,就我所理解的而言,这无济于事。

顺便说一下。我想它应该很清楚,但只是重复一遍:需要两个更改来支持java中提供的注释。

  1. 语言需要扩展注释,例如源代码中的methodes,properites,classes,....
  2. 访问带注释的信息需要标准接口。这只能由苹果提供。
  3. 大多数替代解决方案将注释信息移动到运行时并定义自己的界面。 objective-c运行时提供了一个标准接口,但只有一些技巧,你可以注释属性,仍然是运行时群体。

    suche特征的典型用例是IOC容器(在Java中,例如Spring),它使用带注释的信息来注入其他对象。

    我建议为Apple提供一项功能,以支持此功能。

答案 5 :(得分:0)

你的问题的答案是Objective-C没有Java / C#中的注释的直接等价,虽然有些人建议你可以沿着相同的线条设计一些东西但它可能要么远太多的工作或不会通过集合。

为了满足您的特殊需求,请参阅this answer,其中显示了如何构建一个只保存一种类型对象的数组;与参数类型/泛型一样,强制执行是动态的而不是静态的,但这就是您使用注释获得的内容,因此在这种情况下它可能与您的特定需求相匹配。 HTH。

答案 6 :(得分:0)

您需要的是Objective-C的元数据解析器。我使用了ObjectiveCAnnotate(编译时可检索)和ROAnnotation(运行时可检索)。