Question

I am trying to learn how to take advantage of the objective-c runtime functions.

I have a dictionary that contains several name=value pairs.

E.g.

{
    "recipe_description" = "Delicious and healthy.";
    "recipe_id" = 7042366;
    "recipe_image" = "http://www.fatsecret.com/static/recipe/b5b8ccb7-badd-4a7f-8dd4-0ffe4aba8c6d.jpg";
    "recipe_name" = "Brown Rice & Cherry Tomato Cooked Salad";
    "recipe_url" = "http://www.fatsecret.com/recipes/brown-rice-and-cherry-tomato-cooked-salad/Default.aspx";
}

First, I create a runtime class which contains ivars associated with the keys of each object in the dictionary (e.g. ivars = recipe_description, recipe_id, recipe_image, etc). Second, I set the values of each Ivar in the runtime class to each corresponding object in the dictionary (e.g. recipe_description = Delicious and healthy, etc). Finally, I retrieve the value of Ivar.

I can retrieve the values of recipe_name, recipe_id, and recipe_description, but I am unable to retrieve the values of recipe_url and recipe_image. When I attempt to retrieve these values I get a EXC_BAD_ACCESS code=2, address=0x5 error on the line value = object_getIvar(classInstance, ivar); in the valueForIvarContainingName:class: method.

Code:

- (Class)wrapObjectWithName:(NSString *)name ivarNames:(NSArray *)ivarNames
{
    const char *className = [name cStringUsingEncoding:NSASCIIStringEncoding];

    Class objectClass = objc_allocateClassPair([NSObject class], className, 0);

    for (NSString *key in ivarNames)
    {
        const char *iVarName = [key cStringUsingEncoding:NSASCIIStringEncoding];

        class_addIvar(objectClass, iVarName, sizeof(NSString*), log2(sizeof(NSString*)), @encode(NSString*));
    }

    objc_registerClassPair(objectClass);

    return objectClass;
}

- (void)mapValues:(NSDictionary *)dictionary toVariablesInClass:(id)classInstance
{
    NSArray *dictionaryObjectKeys = [dictionary allKeys];

    for (NSString *key in dictionaryObjectKeys)
    {
        const char *iVarName = [key cStringUsingEncoding:NSASCIIStringEncoding];
        Ivar ivar = class_getInstanceVariable([classInstance class], iVarName);

        id value = dictionary[key];

        object_setIvar(classInstance, ivar, value);
    }
}

- (id)valueForIvarContainingName:(NSString *)anIvarName class:(id)classInstance
{
    unsigned int outCount;
    Ivar *iVarList = class_copyIvarList([classInstance class], &outCount);

    id value;

    for (int i = 0; i < outCount; i++)
    {
        Ivar ivar = iVarList[i];

        NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSASCIIStringEncoding];

        if ([ivarName rangeOfString:anIvarName].location != NSNotFound)
        {
            value = object_getIvar(classInstance, ivar);
            break;
        }
    }

    free(iVarList);

    return value;
}

Usage:

         NSArray *ivarNames = [dictionary allKeys];
         Class FSRecipe = [self wrapObjectWithName:@"FSRecipe" ivarNames:ivarNames];

         id recipe = [[FSRecipe alloc] init];
         [self mapValues:dictionary toVariablesInClass:recipe];

         NSLog(@"%@", [self valueForIvarContainingName:@"image" class:recipe]);

Why can I retrieve the recipe_name, recipe_description, recipe_id values, but not the recipe_url and recipe_image values?

I'm guessing it has something to do with the objects being URLs, maybe? I've tried converting each object in the dictionary to a string, but that has no effect.

Any help is greatly appreciated!

Was it helpful?

Solution

I ended up using valueForKey: instead, which is probably a better choice.

E.g.

id value = [MyCustomClassInstance valueForKey:@"key"];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top