0

Below there are two methods to programmatically alloc and init objects of various classes and 'types'.

- (id)buildObjectOfClass:(NSString *)classString andType:(NSString *)typeString
    {
    id buildObject;
    Class className             = NSClassFromString(classString);
    SEL initWithTypeSelector    = NSSelectorFromString(@"initWithType:");

    if ([className instancesRespondToSelector:initWithTypeSelector] == YES) {
        buildObject = [[className alloc] performSelector:initWithTypeSelector 
                                              withObject: typeString];
    }
    return buildObject;
}

This method implementation was originally written more tersely as simply:
{ return [[className alloc] initWithType:typeString]; }

My questions are: 1) is the verbose version necessary? and 2) if so, was it programmed as best as it could be? Are there shortcuts or best practices I am neglecting?

1
  • 1
    Can you explain the why of this? I can't think of a single instance where I would ever want to do this. You're opening yourself up to a lot of errors/crashes by building classes and selectors from strings. Commented May 14, 2013 at 16:30

1 Answer 1

2

The difference between the verbose and terse versions of this method are that the verbose version validates that the class instances can actually respond to -initWithType: which is not a standard NSObject init function.

It is unnecessary to use the verbose version if any of the following were true:

  • You are only using -init and not -initWithType:
  • You are certain that every class you instantiate will be able to handle -initWithType:
  • You don't mind the application unexpectedly quitting with an unknown method exception if the class you instantiate does not respond to -initWithType:

This version (although you should set buildObject to nil to handle the error case explicitly) returns nil if the class isn't found or if it doesn't respond to -initWithType:. The terse version returns nil if the class isn't found and throws an exception if the class instances don't respond to -initWithType:.

Sign up to request clarification or add additional context in comments.

5 Comments

The long version returns nil when the respondsToSelector: check fails only when compiling under ARC. Otherwise it returns garbage.
@JoshCaswell I believe I made a specific reference to that fact at the start of my final paragraph.
I was replying directly to that. That sentence reads to me as if you're saying that buildObject will always be nil if the instance does not respond to initWithType:. That's not true if ARC is not enabled.
@JoshCaswell Specifically: although you should set buildObject to nil to handle the error case explicitly is what I'm talking about. It's true that I don't specifically call out ARC vs non-ARC, but it's bad form regardless in any C-variant language to return an uninitialized value.
Yes, we agree about that practice. What I'm saying is that your statement «This version ... returns nil if the class isn't found or if it doesn't respond to -initWithType:.» is not correct without including ARC as a condition. ARC initializes object variables to nil; without it they are like any other stack variable and point to junk. And this is exactly why it should be initialized manually.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.