I would like to know how to create an object of the specified Class in objective c. Is there some method I am missing in the runtime docs? If so what is it? I would like to be able to do something like the following:
NSDictionary *types;
-(id<AProtocol>) createInstance:(NSString *) name
{
if ((Class cls = [types objectForKey:name]) != nil)
{
return new Instance of cls;
}
else
{
[NSException raise:#"class not found" format:#"The specified class (%#) was not found.", name];
}
}
please note that name is not a name of the class, but an abbreviation for it, and I cannot do what is indicated in Create object from NSString of class name in Objective-C.
A simple [[cls alloc] init] will do the trick.
As cobbal has mentioned [[cls alloc] init] is usual practice. The alloc is a static class method, defined in NSObject, that allocates the memory and init is the instance constructor. Many classes provide convenience constructors that do this in one step for you. An example is:
NSString* str = [NSString stringWithString:#"Blah..."];
Note the * after NSString. You're working essentially with C here so pointers to objects!
Also, don't forget to free memory allocated using alloc with a corresponding [instance release]. You do not need to free the memory created with a convenience constructor as that is autoreleased for you. When you return your new instance of cls, you should add it to the autorelease pool so that you don't leak memory:
return [[[cls alloc] init] autorelease];
Hope this helps.
Related
When I'm creating custom classes, I'd like to be able to skip the alloc init part of the code once I go to construct an instance of the class. Similar to how it's done with:
NSString * ex = [NSString stringWithFormat...];
Basically I already have the class set up with a custom initializer method to set up my basic variables. However, when I'm on the front end and actually making these critters I have to say:
[[Monster alloc] initWithAttack:50 andDefense:45];
and I'd rather be able to say
[Monster monsterWithAttack:50 andDefense:45];
I know it's a simple stupid thing to just get rid of the alloc part but it makes the code more readable so I'd prefer to do it that way. I originally tried just changing my method from
-(id)initWithAttack:(int) a andDefense:(int) d
to
-(id)monsterWithAttack:(int) a andDefense:(int) d
and then changing my self = [super init] to self = [[super alloc] init]; but that clearly doesn't work! Any ideas?
You have to make a class method
+(id)monsterWithAttack:(int) a andDefense:(int) d
in which you create, initialize, and return an instance (and don't forget your memory management):
+(id)monsterWithAttack:(int) a andDefense:(int) d {
// Drop the autorelease IF you're using ARC
return [[[Monster alloc] initWithAttack:a andDefense:d] autorelease];
}
What you want is a convenience constructor. It's a class method that returns a useable instance of a class and allocates memory for it at the same time.
-(id)initWithAttack:(int)a andDefense:(int)d;
+(id)monsterWithAttack:(int)a andDefense:(int)d;
+(id)monsterWithAttack:(int)a andDefense:(int)d {
//-autorelease under MRC
return [[[self class] alloc] initWithAttack:a andDefense:d];
}
-(id)initWithAttack:(int)a andDefense:(int)d {
self = [super init];
if (self){
//custom initialization
}
return self;
}
You should use a class factory method in the header of monster class.
+(id)monsterWithAttack:(int) attackValue andDefense:(int) defenseValue
in the implementetation of monster class
+(id)monsterWithAttack:(int) attackValue andDefense:(int) defenseValue {
return [[[[self class] alloc] initWithAttack:attackValue andDefense:defenseValue] autorelease];
}
The use of [self class] guarantees the correct dispatch during subclassing. If you are using ARC you can avoid the autorelease method
Class methods of this type use autorelease.
So for instance, you might say:
+ (id)
monsterWithAttack:(int) a
defense:(int) d
{
return [[Monster alloc] initWithAttack:a defense:d]
autorelease];
}
is smth. like this legit? it compiles and looks running ok, but is it ok? (aim setting myself to nil, inside my method)
i mean iam setting myself static to nil, in a method
static MyClass * StaticInstance = nil;
+ (MyClass *) sharedStaticInstance
{
if (StaticInstance == nil) {
StaticInstance = [[MyClass alloc] init];
}
return StaticInstance;
}
- (void) killStaticSelf
{
StaticInstance = nil;
}
and later
[[MyClass sharedStaticInstance] doSmth]; // our static instance is created
[[MyClass sharedStaticInstance] killStaticSelf]; // now its killed inside itself method
[[MyClass sharedStaticInstance] doSmth]; // now it should recreate again
Its having a memory leak.
You should dealloc the StaticInstance first and then you should assign nil to it.
Yes, that's how it's done. I use the sharedStaticInstance often, though I don't usually create a destructor it's probably a good idea, as long as all references to the shared instance in this class pass through sharedStaticInstance first.
EDIT: I just noticed that killStaticSelf is an instance method - it should be a class method I believe, but there shouldn't be any issue either way.
[MyClass killStaticSelf];
Even as the function stack closes, since sending messages to nil doesn't cause issues in Objective-C.
your sharedInstance method is not thread safe so you could get a race condition in this code:
if (StaticInstance == nil) {
StaticInstance = [[MyClass alloc] init];
}
- (void) killStaticSelf
{
StaticInstance = nil;
}
the above code has a leak since you do not provide StaticInstance as a retain property (apparently). You could instead wrap your singleton code in a property but that uses the same static instance.
It's legit, but you need to release the variable before setting it to nil, to avoid memory leaks if you're not using ARC.
Though comprehension of such singleton usage logic is beyond my humble brain abilities.
Instead of recreating an object over and over again, is there a way I can check if an object exists in an if statement?
Thanks!
Assuming your object reference is set to nil if there is no object, then you can use
NSThing *myobj = nil;
if (!myobj)
myobj = [[NSThing alloc] init];
[myobj message];
Depends on your situation. You could use a static variable, i.e.
- (void) doSomething
{
static id foo = nil;
if (! foo)
foo = [[MyClass alloc] init];
// Do something with foo.
}
The first time -doSomething gets called, MyClass will be instantiated. Note that this isn't thread-safe.
Another way is to use a singleton. Possibly a better way is to instantiate the object when the application has finished launching and pass the object to any other objects that might need it.
The thread safe common way to initialize some instance using GCD is as follows:
static dispatch_once_t once;
dispatch_once(&once, ^{
obj = [NSSomeThing new];
});
I want to use this for an object factory: Given a string, create a Class, and if
this Class supports a protocol (with a Create() method) then alloc the class and call
Create.
NSString *className; //assume this exists
Class class = NSClassFromString(className);
if ([class conformsToProtocol:#protocol(SomeProtocol)]) {
id instance = [[class alloc] init];
[instance create];
}
Class klass = NSClassFromString(classname);
if ([klass instancesRespondToSelector:#selector(create)]) {
[[klass alloc] create];
}
May I, however, point out just how many awful Objective-C rules you're breaking by doing the above? For example, you should never be calling methods on an allocated-but-not-initialized instance. The Xcode Static Analyzer will give you all sorts of warnings about memory leaks.
A better option would be this:
[[[klass alloc] init] create];
But you seem to imply that you don't want to call init.
You could consider a class method: [klass create], which would return a non-owned instance of klass. Then you'd just check [klass respondsToSelector:#selector(create)] before calling it.
I have seen a lot of talk about dynamic typing in objective-c. But i haven't seen any examples of what i think it is supposed to be.
lets say I have a generic function that is supposed to juggle two objects (one gets allocated and the other gets freed) and the calling object attaches it self to the newly alloced object. Both are inherited from class0
Please feel free to interpret this however you want if you think it will explain something!!
If the class is picked at runtime, how do i deal with the arguments list (? is a placeholder for now)
How do i alloc a object who's class is not defined until runtime?
-(void) juggle:(?*)objclass1:(?*)objclass2{
? temp = [? alloc] init];
objclass1 = temp;
[temp release];
[objclass2.view removefromsuperview];
[self.handle insertsubview:objclass1.view];
}
I have no idea what the code you have there is trying to do, it is not syntactically valid, and manipulating views has nothing to do with your questions. Anyway, if you really don't know the type you generally use "id" which is type cast to a "void *" for codegen. It has the special property that it is assumed to receive any message, so it does not trigger compiler warnings for unknown messages.
In order to instantiate a class you just need to be holding the "Class" object for it. In Objective C all instances of a class refer to a Class object (the isa pointer in the legacy runtime), which also responds to methods. So in other words, in the following code:
NSArray *myObject = [[NSArray alloc] init];
NSArray is actually an object. So this will generate equivalent code results:
Class myClass = [NSArray class];
NSArray *myObject = [[myClass alloc] init];
or even
Class myClass = NSClassFromString(#"NSArray");
NSArray *myObject = [[myClass alloc] init];
Which uses the function NSClassFromString which walks into the runtime and finds a class with the name you pass in.
All objects return their class if use the class getter, so to instantiate an object that is the same class as an existing object like this:
- (void) leakObjectWithSameClassAs:(id)object {
[[[object class] alloc] init];
}
This is what i have now
- (void)flipfromv1tov2:(UIViewController*)v1:(NSString*)nib1:(UIViewController*)v2{
if(v1 == nil)
{
UIViewController *newview = [[[v1 class] alloc] initWithNibName:nib1 bundle:nil];
v1 = newview;
[newview release];
}
[v2.view removeFromSuperview];
[self.view insertSubview:v1.view atIndex:0];
}
I cannot verify it yet because I have a linking problem...I added this func to my root controller but for some reason I get a warning that the function is implicitly declared. And the build fails because the function call never get linked to anything