C宏公开objective-C中ivar的属性

C宏公开objective-C中ivar的属性,objective-c,macros,Objective C,Macros,在我的项目中,我通常有一个复合对象GameObject,它需要在GameObject的界面中公开ivar的一些属性。例如,游戏对象有一个具有“位置”属性的精灵,我想将精灵的位置用作游戏对象的属性。这很容易做到: // GameObject.h @interface GameObject : NSObject @property CGPoint position; ... @end // GameObject.m @interface GameObject () @property Sprite

在我的项目中,我通常有一个复合对象GameObject,它需要在GameObject的界面中公开ivar的一些属性。例如,游戏对象有一个具有“位置”属性的精灵,我想将精灵的位置用作游戏对象的属性。这很容易做到:

// GameObject.h
@interface GameObject : NSObject
@property CGPoint position;
...
@end

// GameObject.m
@interface GameObject ()
@property Sprite* sprite;   // private property
@end 

@implementation
- (CGPoint)position { return sprite.position; };
- (void)setPosition:(CGPoint)p { sprite.position = p; };
...
作为一个辅助项目,我一直在考虑用C宏生成getter/setter。理想情况下,我能够做到:

@implementation
EXPOSE_SUBCOMPONENT_PROPERTY(subcomponent,propertyName,propertyType);
...
我最近一次失败的尝试是:

#define EXPOSE_SUBCOMPONENT_PROPERTY(sub,property,type) \
- (type)property { id x = sub; return x.##property;} \
- (void)setProperty:(type)set_val { id x = sub; x.##property = set_val; } \
有宏向导可以帮忙吗?
其次,有没有一种方法不需要向宏提供属性的类型?

好吧,您要求这样做,但请做好准备,它很快就会变丑:

#import <objc/runtime.h>

#define EXPOSE_SUBCOMPONENT_PROPERTY(selfClass, sub, property) \

static typeof([[selfClass new] property]) ___get##property(id self, SEL _cmd)\
{\
return ((selfClass *)self)->sub.property;\
}\
static void ___set##property(id self, SEL _cmd, ...)\
{\
selfClass *selfCasted = (selfClass *) self; \
va_list args; va_start(args, _cmd); \
typeof(selfCasted.property) _val = va_arg(args, typeof (selfCasted.property));\
selfCasted->sub.property = _val;\
}\
__attribute__((constructor)) \
static void __init##__property() \
{\
Class cls = [selfClass class];\
class_addMethod(cls, @selector(property), (IMP) ___get##property, "");\
/* for capitalization */ \
char selAsStr[sizeof(#property) + 4] = "set";\
strcat(selAsStr, #property ":");\
selAsStr[3] = toupper(selAsStr[3]);\
class_addMethod(cls, sel_registerName(selAsStr), (IMP) ___set##property, "");\
}\
您不再需要获取返回类型,但必须将类类型发送给方法

必须使用GCC,因为使用扩展的使用广泛,或者,您可以使用C++ 11,但我不推荐使用。
我不建议你使用这个,但是如果你想找一些很酷的东西来捣乱,那就试试吧

好吧,是你自找的,但你要振作起来,它很快就会变丑:

#import <objc/runtime.h>

#define EXPOSE_SUBCOMPONENT_PROPERTY(selfClass, sub, property) \

static typeof([[selfClass new] property]) ___get##property(id self, SEL _cmd)\
{\
return ((selfClass *)self)->sub.property;\
}\
static void ___set##property(id self, SEL _cmd, ...)\
{\
selfClass *selfCasted = (selfClass *) self; \
va_list args; va_start(args, _cmd); \
typeof(selfCasted.property) _val = va_arg(args, typeof (selfCasted.property));\
selfCasted->sub.property = _val;\
}\
__attribute__((constructor)) \
static void __init##__property() \
{\
Class cls = [selfClass class];\
class_addMethod(cls, @selector(property), (IMP) ___get##property, "");\
/* for capitalization */ \
char selAsStr[sizeof(#property) + 4] = "set";\
strcat(selAsStr, #property ":");\
selAsStr[3] = toupper(selAsStr[3]);\
class_addMethod(cls, sel_registerName(selAsStr), (IMP) ___set##property, "");\
}\
您不再需要获取返回类型,但必须将类类型发送给方法

必须使用GCC,因为使用扩展的使用广泛,或者,您可以使用C++ 11,但我不推荐使用。
我不建议你使用这个,但是如果你想找一些很酷的东西来捣乱,那就试试吧

找到了更好的解决方案。诀窍在于理解符号是如何分割的,以便正确使用。此外,还必须为属性声明添加一个宏,以自定义getter/setter名称,从而绕过属性名称大写的问题。对我来说没什么大不了的,帮助我记住它是一种特殊的属性。我能想到的唯一缩减是,由于自定义名称,它们将不兼容KVO

我重命名了宏以便于记忆,它们分别替换了@property和@synthesis,并重新排列了参数顺序以镜像属性

#define PROPERTY_OF_IVAR(prop_type,ivar,prop_name) \
    @property (setter=set_##prop_name:, getter=get_##prop_name) prop_type prop_name \

#define SYNTHESIZE_IVAR_PROPERTY(prop_type,ivar,prop_name) \
    - (prop_type)get_##prop_name { return ivar.prop_name;} \
    - (void)set_##prop_name:(prop_type)set_val { ivar.prop_name = set_val; } \
另一个版本,使@property声明更自然,并且能够在任何深度而不仅仅是ivar属性访问属性,您可以无限期地访问ivar.property.other_property。您还可以将属性的名称设置为与组合对象中的名称不同

// prop_type - type of property that will be exposed
// prop_name - name of property in composing object
#define PROPERTY_OF_IVAR(prop_type, prop_name) \
    (setter=set_##prop_name:, getter=get_##prop_name) prop_type prop_name \

// prop_type - type of property that will be exposed
// prop_path - path to the property you want
// prop_name - must match PROPERTY_OF_IVAR (above)
#define SYNTHESIZE_IVAR_PROPERTY(prop_type, prop_path,prop_name) \
    - (prop_type)get_##prop_name { return prop_path;} \
    - (void)set_##prop_name:(prop_type)set_val { prop_path = set_val; } \
示例用法:

// foo.h
@interface
@property PROPERTY_OF_IVAR(CGPoint, position);
...

// foo.m
@implementation
SYNTHESIZE_IVAR_PROPERTY(CGPoint, sprite.position, position);
...

找到了更好的解决方案。诀窍在于理解符号是如何分割的,以便正确使用。此外,还必须为属性声明添加一个宏,以自定义getter/setter名称,从而绕过属性名称大写的问题。对我来说没什么大不了的,帮助我记住它是一种特殊的属性。我能想到的唯一缩减是,由于自定义名称,它们将不兼容KVO

我重命名了宏以便于记忆,它们分别替换了@property和@synthesis,并重新排列了参数顺序以镜像属性

#define PROPERTY_OF_IVAR(prop_type,ivar,prop_name) \
    @property (setter=set_##prop_name:, getter=get_##prop_name) prop_type prop_name \

#define SYNTHESIZE_IVAR_PROPERTY(prop_type,ivar,prop_name) \
    - (prop_type)get_##prop_name { return ivar.prop_name;} \
    - (void)set_##prop_name:(prop_type)set_val { ivar.prop_name = set_val; } \
另一个版本,使@property声明更自然,并且能够在任何深度而不仅仅是ivar属性访问属性,您可以无限期地访问ivar.property.other_property。您还可以将属性的名称设置为与组合对象中的名称不同

// prop_type - type of property that will be exposed
// prop_name - name of property in composing object
#define PROPERTY_OF_IVAR(prop_type, prop_name) \
    (setter=set_##prop_name:, getter=get_##prop_name) prop_type prop_name \

// prop_type - type of property that will be exposed
// prop_path - path to the property you want
// prop_name - must match PROPERTY_OF_IVAR (above)
#define SYNTHESIZE_IVAR_PROPERTY(prop_type, prop_path,prop_name) \
    - (prop_type)get_##prop_name { return prop_path;} \
    - (void)set_##prop_name:(prop_type)set_val { prop_path = set_val; } \
示例用法:

// foo.h
@interface
@property PROPERTY_OF_IVAR(CGPoint, position);
...

// foo.m
@implementation
SYNTHESIZE_IVAR_PROPERTY(CGPoint, sprite.position, position);
...

你有没有研究过@synthesis?我不确定你是否完全阅读了我的问题。我希望ivarsprite的propertyposition是封闭对象gameObject的属性-使用gameObject.position而不是gameObject.sprite.position。如果“@synthetic”更神奇,我就可以做“@synthetic position=sprite.position;”您可以始终使用bindings+KVO…关键是我不想在我的公共界面中公开精灵的其余属性。我没有把它绑定到任何东西上,我只是需要访问权限。例如,其他地方可能是“if gameObject.position.x>someX”{…'好的,让我想点什么,给我几分钟。你看过@synthesis了吗?我不确定你是否完全读过我的问题。我想要一个ivarsprite的属性position是封闭对象gameObject的属性-使用gameObject.position而不是gameObject.sprite.position。如果@synthesis”更神奇,我就可以做到“@synthetic position=sprite.position;”您可以始终使用绑定+KVO…关键是我不想在我的公共界面中公开sprite的其余属性。我没有将其绑定到任何东西,我只需要访问。例如,其他地方将是“if gameObject.position.x>someX”{…'好吧,让我来做点什么,给我几分钟。