15

Im was looking the REMenu lib code, and see a vars being declared as wiht ({ ... }); .. looks something like 'closure' to lazy evaluated code.. I don't know.. Someone can explain me?

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;
    });
seufagner
  • 1,290
  • 2
  • 18
  • 25

1 Answers1

22

This is a GNU (non-standard) C language extension called a “statement expression”. The syntax is supported by gcc, clang, and several other compilers.

Basically, it lets you treat an arbitrary block as a single expression, whose value is the value of the last statement in the block.

This extension is mostly useful is macro definitions. In my opinion, the code you quoted in your question (from the showFromRect:inView: method in REMenu.m) would be better if it did not use statement expressions. Instead, the code in those statement expressions should be factored out into separate methods. For example:

    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;
}
Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • nice @rob, thanks. Then, I believe that the single benefit is, in this case, group initialization code. no? – seufagner Nov 01 '13 at 17:40
  • 2
    I'm trying hard to not like this, but it is growing on me. @seufagner Right -- it effectively says *the _menuWrapperView ivar is initialized by this self contained block of code, no more, no less*. It certainly makes refactoring easier (just grab the assignment + the whole scope, cut...scroll.. paste). It is also pretty readable. The trailing `view;` looks a bit odd, but I'd bet the compiler would complain mightily if it were omitted. – bbum Nov 01 '13 at 17:42
  • 2
    @bbum We already have a syntax that effectively says “*the _menuWrapperView ivar is initialized by this self contained block of code, no more, no less.*” See my update. Perhaps if the statement expression referred to a lot of variables defined in the enclosing function, the use would be justified. In this case, it only refers to `self`, but you have to inspect the code to discover that, which (in my opinion) makes the use of statement expressions here strictly worse than function calls. – rob mayoff Nov 01 '13 at 17:46
  • 3
    @robmayoff I mostly agree with your edit. The issue, though, is that many views that are, effectively, a conglomerate of other views there should only be one instance of each of the other views. Those instances are created at instantiation of the encapsulating view and their lifespan is tightly bound to the container. Thus, a 'factory like' method isn't really of value. Lazy initialization could be used (i.e. first execution of getter) but that simply makes the instantiation relatively non-deterministic. Keeping all the view configuration code in a -configureSubviews method seems natural. – bbum Nov 01 '13 at 17:49