代码之家  ›  专栏  ›  技术社区  ›  Lavi Avigdor

在目标C的懒惰实例化中,我们为什么不触摸setter呢?

  •  3
  • Lavi Avigdor  · 技术社区  · 12 年前

    在目标C中,以惰性方式实例化内部类数组(等等)是一种常见的做法。

    因此,如果调用getter,它首先检查数组是否为nil,并在需要时为其分配内存。

    但是呢 设置器 ? 如果您试图将某个值插入其中一个数组单元, 因为我们还没有为它分配内存 -它去哪里了?

    很明显,我错过了一些东西。很乐意得到澄清。

    2 回复  |  直到 12 年前
        1
  •  4
  •   Odrakir    12 年前

    我不确定我是否理解你的问题,但如果你这样做:

    @property (nonatomic, strong) NSMutableArray* myArray;
    ...
    
    - (NSMutableArray *) myArray {
        if(!_myArray) {
            NSLog(@"created");
            _myArray = [[NSMutableArray alloc] init];
        }
    
        return _myArray;
    }
    
    ...
    [self.myArray addObject:@"test"];
    

    当你打电话的时候,getter实际上被呼叫了 addObject: ,所以您将看到“已创建”被记录。

        2
  •  3
  •   rismay    12 年前

    因此,在对象的情况下,@property声明是声明指向实例变量的指针的语法糖。“nonatomic”指的是自动创建的getter和setter的类型(在本例中为“非线程安全”)。“strong”是ARC增加变量保留计数的指标。

    因此,当您声明:

    @property (nonatomic, strong) NSMutableArray* myArray;
    

    这就是在类中真正创建的内容——只是指向隐藏实例变量的指针。

    @implementation MyClass {
        NSMutableArray *_myArray;
    }
    

    正如您在getter中看到的,您正在初始化_myArray指针以指向一个新的NSMutableArray:

    - (NSMutableArray *) myArray {
        if(!_myArray) {
            NSLog(@"created");
            _myArray = [[NSMutableArray alloc] init];
        }
    
        return _myArray;
    }
    

    然而,在setter中,您只是在更新指向已经创建的变量的指针。

    self.myArray = [[NSMutableArray alloc] init];
    

    这会向您的班级发送以下消息:

    - (void) myArray: (NSMutableArray *) myArray {
        _myArray = myArray;
    }
    

    正如您所看到的,setter在大多数情况下不需要任何特殊的初始化。唯一要创建自定义setter的时间是要验证传入对象是否具有特殊的财产。一个人为的例子是检查NSMutableArray是否不大于10个对象:

    - (void) myArray: (NSMutableArray *) myArray {
        if (myArray.count < 10) {
            _myArray = myArray;
        }
    }
    

    最后,我想指出的是,您实际上可以使用短三元运算符和括号返回值来延迟实例化对象。例如,以下语句:

    - (NSMutableArray *) myArray {
        return (_myArray = _myArray ?: @{}.mutableCopy);
    }
    

    等于:

    - (NSMutableArray *) myArray {
        if(!_myArray) {
            _myArray = [[NSMutableArray alloc] init];
        }
        return _myArray;
    }
    

    You can even macro this pattern into (WSM is my class prefix):

    #define WSM_LAZY(object, assignment) (object = object ?: assignment)
    

    所以你可以这样写声明:

    - (NSMutableArray *) myArray {
        return WSM_LAZY(_myArray, @{}.mutableCopy);
    }
    

    甚至使用 compound statement syntax 要重写您作为示例介绍的原始setter:

    - (NSMutableArray *) myArray {
        return WSM_LAZY(_myArray, ({
            NSLog(@"created");
            @{}.mutableCopy;
        }));
    }