Romain Dorange
Romain Dorange

Reputation: 831

Instantiate subclass from mother class intelligently

Let's say I have a motheclass (abstract or not) Item and two subclasses ItemA et ItemB which both inherit from Item

All instances are created based on a NSDictionary through the following method

-(id)initWithJSON:(NSDictionary *)d{

//first instantiate common properties from the motherclass
    if ([super initWithJSON:d]){
        //Do specific stuff for the subclass
    }
    return self;
}

Now let's say I fetch from a webservice an array that can contain both ItemA & Item to be created.

Currently what I do is that use a if/then condition to determine which subclass I will instantiate based on the dictionary content, for instance :

 [(NSArray*)data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            if ([obj[@"kind"] isEqualToString:@"A"])
                [interactions addObject:[[ItemA alloc] initWithJSON:obj]];
            else if ([obj[@"kind"] isEqualToString:@"B"])
                [interactions addObject:[[ItemB alloc] initWithJSON:obj]];
            else
            [interactions addObject:[[Item alloc] initWithJSON:obj]];

        }];

Now my point is the following : is there a way to have only one line of code that will - by default - instantiate an Item object, and based on the kind an ItemA or an ItemB In other words, can I write some code in the init method of the motherclass Item to instantiate a subclass instead if some conditions are fulfilled in the NSDictionary parameters which is parsed ?

Thanks

Upvotes: 0

Views: 71

Answers (2)

Paul-Jan
Paul-Jan

Reputation: 17278

Have a look at NSClassFromString .

Example pseudo-code:

NSString *className = [NSString stringWithFormat:@"Item%@", obj[@"kind]];
Class metaClass = NSClassFromString(className);

*instance = [[metaClass alloc] initWithJSON:obj];

You then encapsulate this behavior in a static class factory method to your mother class. See Daij-Djan's answer for details.

Upvotes: 1

Daij-Djan
Daij-Djan

Reputation: 50089

in your mother class, add a convenience method like this:

 +(instancetype)itemWithJSON:(NSDictionary *)obj {
        id item; 

        if ([obj[@"kind"] isEqualToString:@"A"]) {
            item = [[ItemA alloc] initWithJSON:obj];
        } else if ([obj[@"kind"] isEqualToString:@"B"]) { 
            item = [[ItemB alloc] initWithJSON:obj];
        } else {
            item = [[Item alloc] initWithJSON:obj];
        }

        return item;
 }

then use it like this:

 [(NSArray*)data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
     [interactions addObject:[Item itemWithJSON:obj]];
 }];

Upvotes: 2

Related Questions