ObjcClassEnum 1.0.3

ObjcClassEnum 1.0.3

Cătălin Stan 维护。



  • Cătălin Stan

objc-class-enum

为 Objective-C 提供具有类属性的更优雅的枚举。或者如果你愿意,也可以是单例。

在不支持此类构造的语言中,创建更易于表达的平台类似于枚举的结构的一种常见方法是使用 静态 或类属性来封装枚举逻辑。其思想是作为单例公开封装数据对象的具体实例。这种方法有一些优点,因为它消除了需要具有关联值的数组和字典或使用大量的 switch 语句的需要,因为所有数据都被封装在特定的实例中。此外,它可以使使用此类 类枚举 的代码更加易于表达和阅读。这些都不是特定于 Objective-C 的。

@interface Color : NSObject
@property (class, readonly) Color *red;
@property (class, readonly, weak) Color *green;
@end

在 Objective-C 中,这种方法的问题在于需要编写大量的样板代码来设置类属性并实现附加功能,例如遍历枚举成员。如果只需要设置很少的单例,则这可能是可以管理的,但经常存在枚举成员数量为数十甚至数百的情况。编写 50 个以上的看起来都相同的 getter/setter 并为映射其他值到枚举成员设置数组或字典可能会变得繁琐。

这个小库试图去除这些样板代码。我想要一个函数调用就能完成设置样板代码的工作。幸运的是,这是 Objective-C,因此我们可以使用运行时来实现这一点。

设置类枚举

+ (void)initialize {
    assert(class_createEnum(self));
}

您只需要使用 class_createEnum 函数。它将执行以下操作:

  • 设置 getter 实现
  • 如果属性是 readwrite,则设置 setter 实现
  • 设置一个包含所有枚举成员的 NSHashTable 属性,我们可以使用该属性遍历枚举成员。
BOOL class_createEnum(Class cls);

class_createEnum 将认为满足以下条件的属性作为枚举的成员

  1. 属性是 class 类属性
  2. 属性是 @dynamic
  3. 属性类型是类的一个实例
@interface Color : NSObject
@property (class) Color *red;
@end

@implementation Color
@dynamic red;
@end

遍历成员

@property (class, readonly) NSHashTable<Color *> *allColors;

此外,如果 class_createEnum 遇到满足以下条件的属性,它将设置一个 所有成员 属性

  1. 属性是 class 类属性
  2. 属性是 readonly
  3. 属性是 @dynamic
  4. 属性类型是 NSHashTable *
  5. 属性被命名为以下之一:allallMembersallValuesall[ClassName]s(例如,对于 Color 类,是 allColors
@interface Color : NSObject
@property (class, readonly) NSHashTable<Color *> *allColors;
@end

@implementation Color
@dynamic allValues;
@end

调试

提供两个额外的功能用于调试

objc_property_t  * class_copyEnumPropertyList(Class cls, unsigned int *outCount)

这与运行时的 class_copyPropertyList 类似,但返回的是枚举中包含的属性。它需要在调用 class_createEnum 之前进行。必须使用 free() 释放返回的指针。

id class_getEnumValue(Class cls, objc_property_t property)

将获取类 cls 的枚举成员的值,描述为 property

下面是使用上述功能进行调试的示例。

unsigned int count;
objc_property_t *properties;
if((properties = class_copyEnumPropertyList(cls, &count))) {
    for (unsigned int i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSLog(@"%s: %@", property_getName(property), class_getEnumValue(cls, property));
    }
    free(properties);
}

示例

TestApp 中的代码是设置此类的一个好例子,以及如何调试其属性。请在这里查看:https://github.com/thecatalinstan/objc-class-enum/blob/master/TestApp/main.m

以下是使用 Color 类来结构更多与 颜色 相关的信息的最小示例

@interface Color : NSObject

// Class enum (singletons)
@property (class, nonatomic, strong) Color *red;
@property (class, nonatomic, strong) Color *green;

// Example payload
@property NSColor *rawValue;
@property BOOL allowed;

@end

@implementation Color

@dynamic red, green;

+ (void)initialize {
    assert(class_createEnum(self));
    self.red = [Color initWithColor:NSColor.redColor allowed:NO];
    self.green = [Color initWithColor:NSColor.greenColor allowed:YES];
}

@end