2

I have a problem :

I want to use the value of a variable to create an object .

For example , I have a variable myVar.

If myVar == 'Client' :  myVar* obj (obj will be an Client instance)
If myVar == 'People' :  myVar* obj (obj will be an People instance)

Someone can help me ? (sorry for my english)

2
  • as you are comparing myVar with Client. why not to use conditional creation of your obj. Commented May 26, 2013 at 7:06
  • no i don't compare , it's for the explanation: I have a function with a string in parameter. I want create an object using the value of my string. Commented May 26, 2013 at 7:11

1 Answer 1

6

You would use NSClassFromString(@"ClassName") to get the class from a string. To get an instance of the class, you would call alloc and init. For example:

NSString *myString = [NSClassFromString(@"NSString") alloc] init];

If you aren't sure which class you're going to be passing to NSClassFromString, or if you want to pass in different variables, you can use the type id, like so:

id myObject = [NSClassFromString(myVar) alloc] init];

You may have to typecast myObject later on, or reassign it to a typed variable, if you want Xcode to support code completion for that class' properties and methods.

You can read more about NSClassFromString in the developer documentation.

Edit:

Since there's some other discussion going on here about runtime introspection and the "fragile" nature of this code, I'll explain a bit more. The Objective-C runtime supports all kinds of neat tricks, including instantiating classes from strings. Of course you have to be sure that you get back the kind of object that you were expecting in the first place.

The first thing to check after instantiating an object from a class returned by NSClassFromString is if the object is nil. If it is, something went wrong between NSClassFromString and alloc, or between alloc and init. I'd bet your string isn't actually an existing class. So, a slightly safer way to do this is like so:

id myObject = nil;   // Declare a myObject variable. Initialize to nil
Class class = NClassFromString(myVar);

if(!class) 
{ 
  // The class doesn't exist, we can't make the object
}
else 
{
   myObject = [[class alloc] init]; // You can also use [class new] if you're using a vanilla initializer

  if(!myObject) 
  {
     // myObject couldn't be created for some reason...
  }
  else
  {
    // You've got an instance of your class
  }
} 

I'd like to take this a step further though, because the runtime is awesome.

You can also check if a given object can perform some method. To do so, take a look at respondsToSelector:. (Selector means "method name" and is essentially a string.) Assuming we've got a valid object inside of myObject, we can check if myObject can do some action, say, show.

if([myObject respondsToSelector:@selector(show)])
{
   [myObject show]; // Safe to call `show` here
}
else
{
   // Not safe, do something else!
}

I've passed show to @selector because it's a valid method, defined in UIAlertView.h. What if we weren't sure about our selector's existence? Well, we could create a selector from a string, just like we did with the class. Here's how that works:

SEL selector = NSSelectorFromString(@"myCustomMethod");

if ([myObject respondsToSelector:selector])
{
  [myObject performSelector:selector];
}

We create the selector, check if the object implements that method, and if it does, effectively call the method.

When I said that you should check that you got back the kind of object you were expecting, I forgot to mention that you can also ask the runtime if an object's class is equal to a given class. Here's an example of that:

id myObject = [[NSClassFromString(@"UIView") alloc] init];

if([myObject isKindOfClass:[UIView class]])
{
  // We've got a UIView. Set a frame, install it in a hierarchy, or have a drink with it.
}
else
{
  // Mayday!
}

More often then not, you'll want to be checking for specific behaviors rather than classes, but it may be useful to try to instantiate a Class and check if it worked. This helps when you're checking for backwards compatibility on older versions of iOS.

Hope this helps!

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

14 Comments

No...this wont create an instance.
he want of type Client, Bus, Car...not NSString.
Moshe's solution is completly correct in a dynamic typing language as Objective-C. If you do not like that, don't use Objective-C. If you want to restrict the classes (in 99 % you don't want, because it is quite clear, that there is no problem) you should not build a if cascade but use -containsObject (NSSet).
one gotcha about this approach: choosing the correct initializer may require a good chunk of runtime type testing, and it can be difficult to be prepared for any case or assume that a standard initializer (e.g. -init) is also a designated initializer for the dynamic class. several types may not support -init (i.e. they need initialization parameters to be useful) although it is not required that they eliminate support of -init (or other designated initializers of their bases which they do not support).
@Anoop type checking is in many situations simply wrong. Types are /not/ the only way to get save code, but in many situations complex to handle. And this /is/ the /nature/ of objective-c.
|

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.