Skip to content

Instantly share code, notes, and snippets.

@alexdrone
Created June 14, 2018 08:19
Show Gist options
  • Save alexdrone/c26861714760897f0c997a8a2513205a to your computer and use it in GitHub Desktop.
Save alexdrone/c26861714760897f0c997a8a2513205a to your computer and use it in GitHub Desktop.
ARC Struct Boxable Macros
#import <Foundation/Foundation.h>
#define objc_struct_check(__TYPE__, __ACTION__) \
[__ACTION__.identifier isEqualToString: @ #__TYPE__] \
#define objc_struct_define \
typedef struct __attribute__((objc_boxable)) \
#define _objc_boxed_struct_make(__TYPE__, __ARGS__) \
[[objc_boxed_struct alloc] initWithIdentifier:@ # __TYPE__ \
andData:@(__ARGS__)]; \
#define objc_boxed_struct_make(__STRUCT__) \
_objc_boxed_struct_make(__typeof(__STRUCT__), __STRUCT__) \
#define objc_struct_get(__TYPE__, __VAR__, __WRAPPER__) \
__TYPE__ __VAR__; \
assert(objc_struct_check(__TYPE__, __WRAPPER__)); \
[__WRAPPER__.boxedStruct getValue:&__VAR__]; \
NS_ASSUME_NONNULL_BEGIN
/// Wraps a dispatch action.
@interface objc_boxed_struct: NSObject
/// The struct identifier (automatically populated by @c objc_boxed_struct_make).
@property(nonatomic, readonly) NSString *identifier;
/// The boxed struct.
/// @note Use The @c objc_struct_check macro to check the action type and
/// @c objc_struct_get to unbox the arguments.
@property(nonatomic, readonly) NSValue *boxedStruct;
/// Don't use the initializer directly.
/// Use @c objc_boxed_struct_make to build a boxed struct.
- (instancetype)initWithIdentifier:(NSString *)identifier andData:(NSValue *)boxedStruct;
@end
NS_ASSUME_NONNULL_END
#import "objc_struct.h"
@implementation objc_boxed_struct
- (instancetype)initWithIdentifier:(NSString *)identifier andData:(NSValue *)boxedStruct {
if (self = [super init]) {
_identifier = identifier;
_boxedStruct = boxedStruct;
}
return self;
}
@end
@interface test : XCTestCase
@end
objc_struct_define {
NSUInteger count;
NSString *name;
} MyAction1;
objc_struct_define {
NSNumber *number;
} MyAction2;
@implementation test
- (void)testMacros {
MyAction1 arg = {
.count = 0,
.name = @""
};
objc_boxed_struct *userInfo = objc_boxed_struct_make(arg);
if (objc_struct_check(MyAction2, userInfo)) {
XCTFail();
} else if (objc_struct_check(MyAction1, userInfo)) {
objc_struct_get(MyAction1, arg2, userInfo);
XCTAssert(arg2.count == arg.count);
XCTAssert([arg2.name isEqualToString:arg.name]);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment