【问题标题】:C macro to expose property of ivar in objective-cC宏在objective-c中公开ivar的属性
【发布时间】:2012-06-21 23:00:17
【问题描述】:

在我的项目中,我通常有一个复合对象 (GameObject),它需要将 ivar 的一些属性公开到 GameObject 的接口中。例如,一个 GameObject 有一个带有“position”属性的 Sprite,我想使用 Sprite 的位置作为 GameObject 的一个属性。这很容易:

// 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; } \

有任何宏向导可以提供帮助吗? 其次,有没有办法不需要将属性的类型提供给宏?

【问题讨论】:

  • 你看过@synthesize
  • 我不确定您是否完全阅读了我的问题。我希望 ivar(sprite)的属性(位置)成为封闭对象(gameObject)的属性 - 使用 gameObject.position 而不是 gameObject.sprite.position。如果 '@synthesize' 更神奇,我可以做 '@synthesize position = sprite.position;'
  • 你总是可以使用绑定 + KVO...
  • 重点是我不想在我的公共界面中暴露精灵的其余属性。我没有将它绑定到任何东西,我只需要访问。例如,其他地方会是 'if (gameObject.position.x > someX) { ...'
  • 好吧,让我做点什么,给我几分钟。

标签: objective-c macros


【解决方案1】:

好吧,你要求它,但要振作起来,它会很快变得丑陋:

#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,但我不推荐它。

我真的不推荐使用这个,但是如果你想要一些很酷的东西,那就试试吧!

【讨论】:

    【解决方案2】:

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

    我重命名了宏以使其更易于记忆(它们分别替换了@property 和@synthesize),并重新排列了参数顺序以反映属性。

    #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.another_property.indefinitely)。您还可以将属性的名称设置为与其在组合对象中的名称不同。

    // 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);
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-14
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-22
      • 2010-11-08
      相关资源
      最近更新 更多