jspahrsummers / libextobjc

A Cocoa library to extend the Objective-C programming language.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Enhancement] synthesizeAssociation for scalar assign property

neverunlucky opened this issue · comments

Here is an enhancement and I don't know should it be a pull request. But if someone need it just take it.

In the pass time, if I need to add an assign property into the category. I would add one more strong NSValue object and using @synthesizeAssociation, then rewrite setter and getter of the assign property to do the real things. So I modified the synthesizeAssociation to @synthesizeAssociationAssign and automatically change the scalar value into object (using @()) for setter and call the custom method that you should pass in the marco to change back the value for getter.

Here is the usage.

@interface NSObject(ScalarSynthesizeAssociation)
@property (nonatomic, assign) NSInteger myInteger;
@property (nonatomic, assign) CGPoint myPoint;
@end

@implementation NSObject(ScalarSynthesizeAssociation)
@synthesizeAssociationAssign(NSObject, myInteger, NSInteger, integerValue);
@synthesizeAssociationAssign(NSObject, myPoint, CGPoint, CGPointValue);
@end
self.myInteger = 100;
self.myPoint = CGPointMake(100, 200);

Soruce

#define synthesizeAssociationAssign(CLASS, PROPERTY, TYPE, VALUE_SELECTOR) \
	dynamic PROPERTY; \
	\
	void *ext_uniqueKey_ ## CLASS ## _ ## PROPERTY = &ext_uniqueKey_ ## CLASS ## _ ## PROPERTY; \
	\
	__attribute__((constructor)) \
	static void ext_ ## CLASS ## _ ## PROPERTY ## _synthesize (void) { \
		Class cls = objc_getClass(# CLASS); \
		objc_property_t property = class_getProperty(cls, # PROPERTY); \
		NSCAssert(property, @"Could not find property %s on class %@", # PROPERTY, cls); \
		\
		ext_propertyAttributes *attributes = ext_copyPropertyAttributes(property); \
		if (!attributes) { \
			NSLog(@"*** Could not copy property attributes for %@.%s", cls, # PROPERTY); \
			return; \
		} \
		\
		NSCAssert(!attributes->weak, @"@synthesizeAssociation does not support weak properties (%@.%s)", cls, # PROPERTY); \
		\
		objc_AssociationPolicy policy = OBJC_ASSOCIATION_ASSIGN; \
		switch (attributes->memoryManagementPolicy) { \
			case ext_propertyMemoryManagementPolicyRetain: \
				policy = attributes->nonatomic ? OBJC_ASSOCIATION_RETAIN_NONATOMIC : OBJC_ASSOCIATION_RETAIN; \
				break; \
			\
			case ext_propertyMemoryManagementPolicyCopy: \
				policy = attributes->nonatomic ? OBJC_ASSOCIATION_COPY_NONATOMIC : OBJC_ASSOCIATION_COPY; \
				break; \
			\
			case ext_propertyMemoryManagementPolicyAssign: \
                policy = attributes->nonatomic ? OBJC_ASSOCIATION_RETAIN_NONATOMIC : OBJC_ASSOCIATION_RETAIN; \
				break; \
			\
			default: \
				NSCAssert(NO, @"Unrecognized property memory management policy %i", (int)attributes->memoryManagementPolicy); \
		} \
		\
		id getter = ^(id self){ \
			return (TYPE)[objc_getAssociatedObject(self, ext_uniqueKey_ ## CLASS ## _ ## PROPERTY) VALUE_SELECTOR]; \
		}; \
		\
		id setter = ^(id self, TYPE value){ \
			objc_setAssociatedObject(self, ext_uniqueKey_ ## CLASS ## _ ## PROPERTY, @(value), policy); \
		}; \
		\
		if (!class_addMethod(cls, attributes->getter, imp_implementationWithBlock(getter), "@@:")) { \
			NSCAssert(NO, @"Could not add getter %s for property %@.%s", sel_getName(attributes->getter), cls, # PROPERTY); \
		} \
		\
		if (!class_addMethod(cls, attributes->setter, imp_implementationWithBlock(setter), "v@:@")) { \
			NSCAssert(NO, @"Could not add setter %s for property %@.%s", sel_getName(attributes->setter), cls, # PROPERTY); \
		} \
		\
		free(attributes); \
	}

If you guys think it's work and want to mix with the original synthesizeAssociation, welcome to modify it. I think it is possible of using (...) for the TYPE and VALUE_SELECTOR and add some code to make it can used by both assign, strong and copy property.