NSValue and Boxed Expressions
Published on
Few hours ago I finally finished with my patch to Clang. It took a lot of time, but for me it is the most interesting and challenging OSS contribution so far.
I’m not going to dive deep into the details, but will give an overview of the new feature it brings to Objective-C.
For those of you who want to see the code and documentation: code docs
Boxed Expressions and Structures
Boxed expressions got limited support of NSValue:
NSValue *center = @(view.center); // Point p = view.center;
// [NSValue valueWithBytes:&p objCType:@encode(Point)];
NSValue *frame = @(view.frame); // Rect r = view.frame;
// [NSValue valueWithBytes:&r objCType:@encode(Rect)];
To use boxed expressions on a C struct or union you’ve defined, mark it as objc_boxable
first:
struct __attribute__((objc_boxable)) Point {
int x, y;
};
typedef struct __attribute__((objc_boxable)) _Size {
int width, height;
} Size;
For C structs or unions defined in a different part of your code (legacy, third-party), simply ‘enable’ this feature before using it:
typedef struct _Rect {
Point origin;
Size size;
} Rect;
Rect r;
NSValue *bad_rect = @(r); // error
typedef struct __attribute__((objc_boxable)) _Rect Rect;
NSValue *good_rect = @(r); // ok
Availability
To write backward compatible code you need to check for attribute and feature availability:
#if __has_attribute(objc_boxable)
typedef struct __attribute__((objc_boxable)) _Rect Rect;
#endif
CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"];
#if __has_feature(objc_boxed_nsvalue_expressions)
animation.fromValue = @(layer.position);
animation.toValue = @(newPosition);
#else
animation.fromValue = [NSValue valueWithCGPoint:layer.position];
animation.toValue = [NSValue valueWithCGPoint:newPosition];
#endif
[layer addAnimation:animation forKey:@"move"];
Boring Numbers
- 222 days since first version of patch
- 85 commits in an own fork of clang
- 50 emails in the mail thread
- 8 versions of the patch
- 3 different implementations
- 1 retired reviewer
That’s it
It took about 7 months to deliver this feature. While I didn’t work on it every week, it was quite the effort. Nonetheless, the result was worth it. So next time you feel like there is no end in sight with a patch you’re trying to get merged, don’t despair - that sweet LGTM will come!