【问题标题】:Creating a macro to perform default init创建一个宏来执行默认初始化
【发布时间】:2013-03-23 13:43:49
【问题描述】:

我有很多方法重复这个简单的样板:

- (id)myObject {
    if(!_myObject) {
        self.myObject = [_myObject.class new];
    }
    return _myObject;
}

所以我想用一个简单的宏来替换它:

#define default_init(instance) \
    if(!instance) instance = [instance.class new]; \
    return instance;

所以我只需要打电话:

- (id)myObject {
        default_init(_myObject);
}

上面的代码目前可以编译,但问题是宏直接设置了实例变量的值。相反,我想调用 self.instance = value;

所以不是

if(!instance) instance = [instance.class new];

我想要类似的东西;

if(!instance) self.instance = [instance.class new];

但显然当前的代码不允许这样做。我怎样才能完成这样的事情?

【问题讨论】:

    标签: objective-c macros


    【解决方案1】:

    使用这个宏:

    #define default_init(class, instance)      \
        if ( ! _##instance ) {                 \
            self.instance = [class new] ;      \
        }                                      \
        return _##instance
    

    我能够创建这个实例方法:

    - (NSMutableArray*) myObject {
        default_init(NSMutableArray, myObject) ;
    }
    

    我必须添加一个定义类的参数,因为_myObject 仍然是nil,因此_myObject.classnil

    This StackOverflow questionthis Cprogramming page 建议将多行宏包装在 do {...} while(0) 中:

    #define default_init(class, instance)          \
        do {                                       \
            if ( ! _##instance ) {                 \
                self.instance = [class new] ;      \
            }                                      \
            return _##instance ;                   \
        } while(0)
    

    如果你真的想,你可以创建一个定义整个方法的宏:

    #define default_getter(class, instance)        \
        - (class*) instance {                      \
            if ( ! _##instance ) {                 \
                self.instance = [class new] ;      \
            }                                      \
            return _##instance ;                   \
        }
    

    这样使用它:

    default_getter(NSMutableArray, myObject)
    

    【讨论】:

    • 这看起来不错。虽然只是为了挑战,但我想找出一种方法来做到这一点而不通过课程 - 只是财产。我找到了一种方法来做到这一点,但它确实需要一个外部库。查看我发布的答案。
    【解决方案2】:

    我通常不使用宏来构建getter方法,而是声明属性:

    Instance.h

    @interface Instance : NSObject
    @property NSMutableArray* myObject ;
    @end
    

    并覆盖- init 来初始化属性:

    Instance.m

    - (id) init {
        self = [super init] ;
        if ( self ) {
            self.myObject = [NSMutableArray new] ;
        }
        return self ;
    }
    

    【讨论】:

    • 是的,但我想延迟加载
    【解决方案3】:

    好的,这就是我的看法。

    注意:这样做只是为了看看是否可以完成。我认为在运输代码中使用它不是一个好主意。

    首先从libextobjc 导入#import "EXTRuntimeExtensions.h"。那么:

    #define underize(name) _##name
    
    #define property_type(property) \
        property_attr(property)->objectClass
    
    #define property_attr(propertyName) \
        ext_copyPropertyAttributes(class_getProperty(self.class, # propertyName))
    
    #define default_init(propertyName) \
        - (id)propertyName { \
           if(!underize(propertyName)) self.propertyName = [property_type(propertyName) new]; \
           return underize(propertyName); \
    } \
    

    然后说你有一个属性:

    @property (nonatomic) NSArray *myArray;
    

    你可以这样做:

    default_init(myArray);
    

    这会创建一个默认的 getter。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      • 2012-11-29
      • 2011-06-08
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多