Last active
December 12, 2015 08:19
-
-
Save numist/4743302 to your computer and use it in GitHub Desktop.
Function returning something useful for passing directly into `class_addProperty` when copying properties from one class to another.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <objc/runtime.h> | |
// Lifted from https://github.com/numist/Debugger/blob/master/debugger.h | |
#define BailWithBlockUnless(exp,block) \ | |
do { \ | |
if (!(exp)) { \ | |
return block(); \ | |
} \ | |
} while(0) | |
// Like the other class_copy* functions, the caller must free the return value of this function with free() | |
objc_property_attribute_t *nn_property_copyAttributeList(objc_property_t property, unsigned int *outCount) | |
{ | |
void *(^failure)(void) = ^{ | |
if (outCount) { | |
*outCount = 0; | |
} | |
return NULL; | |
}; | |
// For more information about the property type string, see the Declared Properties section of the Objective-C Runtime Programming Guide | |
const char *constAttributes = property_getAttributes(property); | |
BailWithBlockUnless(constAttributes, failure); | |
/** | |
* ┏━━━━━━━━━━━━━━━━┓ | |
* ┃nameptr ┃ | |
* ┃valueptr ┃ | |
* ┠────────────────┨ | |
* ┃nameptr ┃ | |
* ┃valueptr ┃ | |
* ┠────────────────┨ | |
* ┃nameptr ┃ | |
* ┃valueptr ┃ | |
* ┠────────────────┨ | |
* ┃... ┃ | |
* ┠────────────────┨ | |
* ┃NULL ┃ | |
* ┃NULL ┃ | |
* ┠────────────────┨ | |
* ┃N0Valueue0N0Valu┃ | |
* ┃e0N0Valueueueue0┃ | |
* ┃... ┃ | |
* ┗━━━━━━━━━━━━━━━━┛ | |
*/ | |
// Get the number of attributes | |
size_t attributeCount = strlen(constAttributes) ? 1 : 0; | |
for (unsigned i = 0; constAttributes[i] != '\0'; i++) { | |
if (constAttributes[i] == ',') { | |
attributeCount++; | |
} | |
} | |
// Calculate and allocate the attribute list to be returned to the caller | |
size_t attributeListSize = (attributeCount + 1) * sizeof(objc_property_attribute_t); // The list of attributes, plus an extra attribute containing NULL for its name and value. | |
size_t attributeStringsSize = (strlen(constAttributes) + attributeCount + 1) * sizeof(char); // The attribute names and values, plus the extra necessary NUL terminators. | |
objc_property_attribute_t *attributeList = calloc(attributeListSize + attributeStringsSize, 1); | |
BailWithBlockUnless(attributeList, failure); | |
// Initialize the attribute string area. | |
char *attributeStrings = (char *)attributeList + attributeListSize; | |
strcpy(attributeStrings, constAttributes); | |
char *name; | |
char *next = attributeStrings; | |
unsigned attributeIndex = 0; | |
while ((name = strsep(&next, ",")) != NULL) { | |
// Attribute pairs must contain a name! | |
if (*name == '\0') { | |
free(attributeList); | |
return failure(); | |
} | |
// NUL-terminating the name requires first moving the rest of the string which requires some extra housekeeping because of strsep. | |
char *value = name + 1; | |
int remainingBufferLength = (int)attributeStringsSize - (int)(value - attributeStrings); | |
if (remainingBufferLength > 1) { | |
memmove(value + 1, value, remainingBufferLength - 1); | |
// Update next pointer for strsep | |
if (next) next++; | |
} | |
// Add NUL termination to name and update value pointer. | |
*(name + 1) = '\0'; | |
value++; | |
attributeList[attributeIndex].name = name; | |
attributeList[attributeIndex].value = value; | |
attributeIndex++; | |
} | |
if (outCount) { | |
*outCount = attributeCount; | |
} | |
return attributeList; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I just realized, other than the use of blocks, there's nothing innately Objective-C about this function. Success?