2

私のプロジェクトでは、通常、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 マクロを使用してゲッター/セッターを生成することを検討しています。理想的には、私はできるでしょう:

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

助けてくれるマクロウィザードはありますか? 次に、マクロにプロパティの型を指定する必要がないようにする方法はありますか?

4

2 に答える 2

0

あなたはそれを求めましたが、気を引き締めてください、それは醜い速さになります:

#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 を使用することもできますが、お勧めしません。

これを使用することはあまりお勧めしませんが、何かクールなものをいじりたい場合は、試してみてください!

于 2012-06-21T23:54:54.457 に答える
0

より良い解決策を見つけました。トリックは、「##」を適切に使用するために、記号がどのように分割されるかを理解することでした。また、プロパティ宣言にマクロを追加してゲッター/セッター名をカスタマイズする必要がありました。これにより、プロパティの名前を大文字にする問題が回避されました。私にとっては大したことではありませんが、その特別な特性を思い出すのに役立ちます。私が考えることができる唯一のダウンサイズは、カスタム名のために 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);
...
于 2012-06-22T00:50:36.080 に答える