Objective-C使用({ ... })声明变量

15
我查看了REMenu lib的代码,并发现一些变量声明使用({ ... });这样的形式。看起来像是惰性求值(lazy evaluated code)的闭包(closure)……但我不确定,有人可以解释一下吗?
self.menuWrapperView = ({
        UIView *view = [[UIView alloc] init];
        view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        if (!self.liveBlur || !REUIKitIsFlatMode()) {
            view.layer.shadowColor = self.shadowColor.CGColor;
            view.layer.shadowOffset = self.shadowOffset;
            view.layer.shadowOpacity = self.shadowOpacity;
            view.layer.shadowRadius = self.shadowRadius;
            view.layer.shouldRasterize = YES;
            view.layer.rasterizationScale = [UIScreen mainScreen].scale;
        }
        view;
    });

    self.toolbar = ({
        UIToolbar *toolbar = [[UIToolbar alloc] init];
        toolbar.barStyle = self.liveBlurBackgroundStyle;
        if ([toolbar respondsToSelector:@selector(setBarTintColor:)])
            [toolbar performSelector:@selector(setBarTintColor:) withObject:self.liveBlurTintColor];
        toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        toolbar;
    });
1个回答

22

这是一个 GNU(非标准)C 语言扩展,称为“语句表达式”。该语法由gcc、clang和其他几个编译器支持。

基本上,它允许您将任意块视为单个表达式,其值为块中最后一条语句的值。

此扩展在宏定义中非常有用。我认为,在您的问题中引用的代码(来自REMenu.m中的showFromRect:inView:方法)如果不使用语句表达式将会更好。相反,这些语句表达式中的代码应该被分解成单独的方法。例如:

    self.menuWrapperView = [self newMenuWrapperView];
    self.toolbar = [self newToolbar];

...

- (UIView *)newMenuWrapperView {
    UIView *view = [[UIView alloc] init];
    view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    if (!self.liveBlur || !REUIKitIsFlatMode()) {
        view.layer.shadowColor = self.shadowColor.CGColor;
        view.layer.shadowOffset = self.shadowOffset;
        view.layer.shadowOpacity = self.shadowOpacity;
        view.layer.shadowRadius = self.shadowRadius;
        view.layer.shouldRasterize = YES;
        view.layer.rasterizationScale = [UIScreen mainScreen].scale;
    }
    return view;
}

- (UIToolbar *)newToolbar {
    UIToolbar *toolbar = [[UIToolbar alloc] init];
    toolbar.barStyle = self.liveBlurBackgroundStyle;
    if ([toolbar respondsToSelector:@selector(setBarTintColor:)])
        [toolbar performSelector:@selector(setBarTintColor:) withObject:self.liveBlurTintColor];
    toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    return toolbar;
}

不错 @rob,谢谢。那么,我认为在这种情况下,单一的好处就是组初始化代码。对吧? - seufagner
2
我很努力地不喜欢这个,但它正在慢慢地变得越来越好。@seufagner 对--它有效地表示* _menuWrapperView ivar是由这个自包含的代码块初始化的,没有更多,也没有更少*。它确实使重构更容易(只需获取分配+整个范围,剪切...滚动..粘贴)。它也非常易读。尾随的view;看起来有点奇怪,但我敢打赌如果省略了编译器会抱怨不已。 - bbum
2
@bbum 我们已经有了一种有效地表达“* _menuWrapperView ivar 由这个自包含的代码块初始化,没有多余或不足*”的语法。请看我的更新。也许如果语句表达式涉及到在封闭函数中定义的很多变量,使用就是合理的。但在这种情况下,它只涉及到 self,但你必须检查代码才能发现这一点,这使得在这里使用语句表达式比函数调用严格更糟糕(在我看来)。 - rob mayoff
3
我基本上同意你的编辑。问题在于,许多视图实际上是其他视图的集合,每个其他视图应该只有一个实例。这些实例在封装视图的实例化时创建,并且它们的寿命与容器紧密绑定。因此,“像工厂一样”的方法并没有真正价值。可以使用惰性初始化(即getter的第一次执行),但这仅使实例化相对不确定。将所有视图配置代码保留在-configureSubviews方法中似乎很自然。 - bbum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接