// // EXTSynthesize.h // extobjc // // Created by Justin Spahr-Summers on 2012-09-04. // Copyright (C) 2012 Justin Spahr-Summers. // Released under the MIT license. // #import "EXTRuntimeExtensions.h" #import /** * \@synthesizeAssociation synthesizes a property for a class using associated * objects. This is primarily useful for adding properties to a class within * a category. * * PROPERTY must have been declared with \@property in the interface of the * specified class (or a category upon it), and must be of object type. */ #define synthesizeAssociation(CLASS, PROPERTY) \ 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: \ break; \ \ default: \ NSCAssert(NO, @"Unrecognized property memory management policy %i", (int)attributes->memoryManagementPolicy); \ } \ \ id getter = ^(id self){ \ return objc_getAssociatedObject(self, ext_uniqueKey_ ## CLASS ## _ ## PROPERTY); \ }; \ \ id setter = ^(id self, id 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); \ }