我想拥有类级属性,我找到了https://stackoverflow.com/a/15811719/157384的解决方案
@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end
@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end
现在您可以通过属性访问器进行调用,如下所示:
Model.value = 1
Model.value // => 1
奇!
现在,我想让这个代码块以某种形式的宏或元编程重用,它采用属性名称和类型。我们怎么写呢?
通过上面的示例,value
和(int)
(和Model
)应该是动态的。
感谢@Rich,我现在有了这个:
// Common.h
#define CLASS_PROPERTY_INTERFACE(TYPE, METHOD, CMETHOD) \
+ (TYPE) METHOD; \
+ (void) set##CMETHOD:(TYPE)val; \
#define CLASS_PROPERTY_IMPLEMENTATION(TYPE, METHOD, CMETHOD) \
static TYPE _##METHOD; \
+ (TYPE) METHOD \
{ @synchronized(self) { return _##METHOD; } } \
+ (void) set##CMETHOD:(TYPE)val \
{ @synchronized(self) { _##METHOD = val; } } \
// User.h
@interface User : NSObject
CLASS_PROPERTY_INTERFACE(User *, me, Me)
@end
// User.m
@implementation User
CLASS_PROPERTY_IMPLEMENTATION(User *, me, Me)
@end
User.me = currentUser;
User.me // => currentUser
还有一件事要做,就是尽可能自动大写传递给宏的方法名称。
但它已经比它的样板更简洁了!
答案 0 :(得分:2)
这与要求在实例使用的类上动态生成访问器没什么不同。事实上同样的问题。
对于直接对象值而言,无论对象类型如何,都不难做到,并且您可以通过利用关联对象在运行时纯粹生成它们。
但是,使用id
之外的类型信息生成这些要求意味着您已将问题转移到编译时问题。
为此,您几乎可以编写一系列#define
宏来生成您需要的任何代码。你至少需要两个宏;一个用于实现,一个用于接口。
答案 1 :(得分:2)
宏观方式......
注意强>: 这有点可怕,我不建议使用它,但是正在玩它们在宏中定义它们......
对此的警告(除了它不是非常“好”)是setter方法的格式为set_XXX:
。
#define CLASS_INTERFACE(CLS_NAME, METHOD, TYPE) @interface CLS_NAME : NSObject \
+ (TYPE) METHOD; \
+ (void) set_##METHOD:(TYPE)val; \
@end \
#define CLASS_IMPLEMENTATION(CLS_NAME, METHOD, TYPE) @implementation CLS_NAME \
static TYPE METHOD; \
+ (TYPE) METHOD \
{ @synchronized(self) { return METHOD; } } \
+ (void) set_##METHOD:(TYPE)val \
{ @synchronized(self) { METHOD = val; } } \
@end \
将以下内容放在标题文件中:
CLASS_INTERFACE(Test, value, int)
这在.m
个文件中:
CLASS_IMPLEMENTATION(Test, value, int)
然后使用Test
类:
[Test set_value:4];
int i = [Test value];
这又是非常可怕的但是会起作用......!
编辑:
正如评论中提到的,我认为使用单例更好,这让我编写了更可怕的代码:(
现在我们已经准备好(生病袋):
#define SINGLETON_INTERFACE_START(CLS_NAME) @interface CLS_NAME : NSObject \
+(instancetype) sharedInstance; \
#define SINGLETON_INTERFACE_END(CLS_NAME) \
@end \
static inline CLS_NAME * CLS_NAME##Global () { return [CLS_NAME sharedInstance]; }
#define SINGLETON_IMPLEMENTATION(CLS_NAME) @implementation CLS_NAME \
+(instancetype) sharedInstance \
{ \
static id instance; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
instance = [self new]; \
}); \
return instance; \
} \
@end \
在你的标题中:
SINGLETON_INTERFACE_START(Test)
@property (atomic, assign) NSUInteger value;
SINGLETON_INTERFACE_END(Test)
在您的.m
:
SINGLETON_IMPLEMENTATION(Test)
并使用它(可以产生更多的病):
TestGlobal().value = 1;
int i = TestGlobal().value;
或“更好”的Objective-C方式:
[Test sharedInstance].value = 1;
int i = [Test sharedInstance].value;
你甚至可以(Team America现在的病人数量)在界面中有属性#define
。
请注意,我已将@property
中的@interface
定义保留为atomic
,因为OP似乎喜欢使用@synchronized
。这不是必需的,因为它们设置为atomic
。
我知道OP想要类“属性”(只是说这让我颤抖),但还有其他更好的选项!