6

我最近一直在学习 ruby​​,并且基本上爱上了 ||= 功能,因为它可以使在 Objective C 中编写惰性 getter 变得更加容易。

目前我写吸气剂,例如:

- (NSArray *)myArray {
  if (!_myArray) {
    _myArray = [NSArray array];
  }
  return _myArray
}

除非我在 ||= 中遗漏了一些东西,否则我可以使用以下方法在 Ruby 中编写前面的代码:

- (NSArray *)myArray {
  return _myArray ||= [NSArray array];
}

那显然要干净得多。Objective-C 语言/运行时中是否有任何东西可以让你做到这一点?

此外,以下是吸气剂的单行三元组,我不确定它是否与上面发布的经过验证的真实方法一样有效(第一个片段)。有人可以告诉我这样做是否有任何问题:

- (NSArray *)myArray {
  return _myArray = _myArray ? _myArray : [NSArray array];
}
4

2 回答 2

11

最后一个片段与您发布的第一个片段具有相同的效果。

作为一项改进,虽然没有像||=Objective-C 中那样的运算符,但您可以省略三元 if 运算符的第二个参数并执行

return _myArray = _myArray ?: [NSArray array];

这完全等同于

return _myArray = _myArray ? _myArray : [NSArray array];

这是现代版本的gccclang支持的语言扩展。

奖励:如果你想节省更多的击键,你可以做

- (NSArray *)myArray {
    return _myArray = _myArray ?: @[];
}

作为旁注,跳过中间操作数也有一些好处。

例如在这种情况下

id x = [self someMethod] ? [self someMethod] : [self anotherMethod];

ifsomeMethod评估true它会被调用两次,而做

id x = [self someMethod] ?: [self anotherMethod];

它只会被调用一次。

于 2013-10-26T03:22:40.870 回答
3

没有字面上的等价物,除非你想破解 Clang。逻辑运算符虽然||短路,但不会计算其操作数。使用三元条件的宏将使您接近:

#define NON_NIL(o, p) ((o) ? (o) : (p))

- (NSMutableArray *)myArray
{
    return _myArray = NON_NIL(_myArray, [NSMutableArray array]);
}

因为 C 中的赋值有点像表达式,并计算为赋值。

您实际上也可以制作一个OR_ASSIGN()宏,但我将把它留给完全精神错乱的读者作为练习。

也许同样疯狂的是一个函数:

id lazySet(id *obj; id(^valBlock)(void))
{
    if( !(*obj) ){
        *obj = valBlock();
    }
    return *obj;
}

- (NSMutableArray *)myArray
{
    return lazySet(&_myArray, ^{return [NSMutableArray array]});
}

但这越来越荒谬了。

于 2013-10-26T04:19:01.040 回答