Skip to content

Instantly share code, notes, and snippets.

@numist
Last active December 12, 2015 08:19
Show Gist options
  • Save numist/4743302 to your computer and use it in GitHub Desktop.
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.
#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;
}
@numist
Copy link
Author

numist commented Mar 7, 2013

I just realized, other than the use of blocks, there's nothing innately Objective-C about this function. Success?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment