在目标 C 惰性实例化中,我们为什么不触摸二传手?



在目标C中,通常的做法是以懒惰的方式实例化内部类数组(等(。

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

但是二传手呢?如果您尝试将一些值插入到其中一个数组单元格中,因为我们还没有为它分配内存 - 它去哪里了?

显然,我在这里错过了一些东西。很乐意澄清。

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

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

当您调用 addObject: 时,getter 实际上被调用,因此您将看到正在记录"已创建"。

因此,@property声明是语法糖,用于声明对象指向实例变量的指针。"非原子"是指自动创建的 getter 和 setter 的类型(在本例中为"非线程安全"。而"强"是 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 大多数时候不需要任何特殊的初始化。只有在要验证传入对象具有特殊属性时,才要创建自定义资源库。一个人为的示例是检查 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;
}

您甚至可以将此模式宏化为(WSM 是我的类前缀(:

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

所以你可以写这样的语句:

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

或者甚至使用复合语句语法重写您作为示例提供的原始 setter:

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

最新更新