October 02, 2014

Setting structures in Objective-C

You know how you always do this little dance to update couple of values on a structure property

CGRect frame = self.view.frame;
frame.size.width = 100;
frame.origin.y = 30;
self.view.frame = frame;

There is a better way!

First, let’s start with a sligtly better way. If you don’t want to polute your scope with temporary variables (let’s say you have to change five different view’s frames)

self.view.frame = ({
   CGRect frame = self.view.frame;
   frame.size.width = 100;
   frame.origin.y = 30; 
   frame;
});

This code utilizes C feature of scopes but looks kind of ugly. That’s where C macros can help:

#define WMLSetStructure(object, key, setterBlock) ({\
    if (NO) {(void)((object).key);}\
    object.key = ({\
        typeof(object.key) key = object.key;\
        setterBlock;\
        key;\
    });\
})

Here is how to use it

WMLSetStructure(self.view, frame, {
    frame.origin.y = 30;
    frame.size.width = 100;
});

WMLSetStructure(self.mapView, region, {
    region.center.longitude -= 0.0001;
    region.span.latitudeDelta += 3.1415;
});

It creates a local vairable with the same name as the property and returns it at the end of the scope.

The only thing I don’t like about it is the need to separate object with key, I do it to provide you with the variable with the same name as the key in the setter scope.

Oh and see that line

if (NO) {(void)((object).key);}

it helps to autocompete key according to the list of properties this object has.