Objective-C Tricks: Scope your Assignments
March 14, 2014
There’s a new Objective-C pattern I’ve been experimenting with lately, which looks like this:
- (void)viewDidLoad;
{
[super viewDidLoad];
self.shareButton = ({
CGFloat xPos = self.view.width - 80.0f;
CGFloat yPos = self.view.bottom - 44.0f;
CGRect frame = CGRectMake( xPos, yPos, 70.0f, 44.0f );
UIButton *button = [[UIButton alloc] initWithFrame:frame];
UIImage *normal = [UIImage imageNamed:@"share.png"];
UIImage *disabled = [UIImage imageNamed:@"share-disabled.png"];
[button setImage:normal forState:UIControlStateNormal];
[button setImage:disabled forState:UIControlStateDisabled];
[button addTarget:self action:@selector(share:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
button;
});
}
This syntax probably isn’t familiar to Objective-C programmers, but it’s actually simple. It’s a trick that takes advantage of a compiler extention where putting a variable by itself as the last line within () braces acts as “returning” that variable, meaning you can use the whole expression as an assignment.
What’s the point? Chances are you’ve worked on an iOS app or two where some big controller class had a viewDidLoad method that’s grown out of control. The kind of class that’s managing a dozen views, each with their own content, setup, positioning and so on. In these classes the viewDidLoad method can be hundreds of lines long, impossible to quickly read and parse, and require refactoring for even small changes.
The advantage of this syntax is that it wraps each assignment into a neat little bundle, no matter how much extra work is related to it. Temporary variables, subviews, configuration and whatnot all live within the scope’s braces, so it’s easy to see at a glance what code belongs to each specific object. You can give temporary variables nice names too, since they all live within their own scope. Ever have a method where you have to name things like passwordFieldFrame, confirmPasswordFieldFrame, …? Now each of those CGRects can just have the nice, short name “frame” without worrying about stepping on the toes of another object.
There’s an argument to be made against this syntax, and I’m not completely sold on the idea. In an ideal world you’d want to split these view controllers into more managable subcontrollers, instead of trying to pretty up the mess. It’s also a little hacky, relying on a language feature that’s not intended for this purpose. But despite these problems I still kind of like what it does. It’s hard to say no to anything that makes code more manageable and easy to read.