Is it ok to allocate released object again? - objective-c

if i did this
Object * myObject = [[Object alloc]init];
[myObject release];
is there anything wrong about allocating my object in next line
myObject = [[Object alloc]init];
again?

This is safe to do.
The reason is that myObject is not an object, it's a reference (or pointer if you want to be exact) to the object. That means you've got 2 completely independent objects, but you forget about the reference to the first.

No problem at all.
[myobject release]; releases the object pointed at by myObject.
Later, myobject = [[Object alloc] init]
will make myobject point to another object.

There is nothing wrong with that. That is how you make sure you don't leak your first object.
However, you are not technically allocating the released object again. You are just using the old pointer again.
Object * myObject = [[Object alloc]init];
myObject = [[Object alloc]init];
will result in leaking the first object you created.

yes of course. this technique is specially useful in local method variables where you can reuse the object declared once by reallocating it again as new object..!!

Related

Reassigning an object with ARC

If I've created an NSArray in the init of an object.
Then later on I want to recreate a new NSArray to the same property should I set the old one to nil first?
i.e.
is it ok to just go...
self.arrayProperty = [[NSArray alloc] init];
or should I do...
self.arrayProperty = nil;
self.arrayProperty = [[NSArray alloc] init];
(I'm just using an array for the sake of this example but it's a general questions about properties).
If it makes any difference, it's a strong property.
The first approach is fine, you don't need to set it explicitly to nil before assigning a new object, since the setter releases the backing object of the property before retaining and assigning the new one. Just what you would do under MRC (except that here you don't autorelease the object).
It's just the same, as with ARC an object dies when there are no more references to it. The only difference is that in the second code you're doing a useless extra operation.

Alloc a new objective C object to a retained property?

Sorry for asking a totally basic question, but if I have a synthesized property that is retained.
self.myProperty = [[NSObject alloc] init];
will cause a memory leak?
So am I correct in thinking that I need to do
self.myProperty = [[NSObject alloc] init];
[self.myProperty release];
in order to balance? Because that seems dumb.
Standard practice would be to use autorelease in that situation. So:
self.myProperty = [[[NSObject alloc] init] autorelease];
This is because init returns a retained object, and since your property also retains it, you'll have to release it.
Edited to add: #walkytalky makes a good point in the comments that it is actually alloc that retains the object, init just returns it.
Here is a thread that you will find helpful.
You are correct. Without ARC, any property that is retained needs to be released as well.
You can also do:
self.myProperty = nil;
From the docs:
retain
Specifies that retain should be invoked on the object upon
assignment.
The previous value is sent a release message.
Another (more verbose) technique is to do:
NSObject *o = [[NSObject alloc] init]; //retain count 1
self.myProperty = o; //retain count 2
[o release]; //retain count 1
Personally though, I'd probably just use autorelease as in the first example above.
With ARC enabled, xcode will handle alle the memory management.
When not using ARC be sure to release it in the dealloc method.

NSMutableArrays - can I do this?

In my app, the singleton class (SharedData) allocates memory for a NSMutableArray:
[self sharedMutableArray] = [[NSMutableArray alloc] init];
Class A populates the this sharedMutableArray:
NSObject *obj = [NSObject alloc] init];
[sharedMutableArray addObject];
obj = nil;
Class B does this - and that's my question:
NSMutableArray *tmpArray = sharedMutableArray;
... uses the tmpArray locally
[tmpArray removeAllObjects];
tmpArray = nil;
This is an inherited code and my hunch is that this is a NO-NO. Can some one confirm that assigning nil to tmpArray will release memory for sharedMutableArray also.... I guess the author wanted to release tmpArray only...
Assigning nil to tmpArray only sets your pointer to the object to nil. It does not affect the object itself (or its lifecycle) at all. In this case, setting the objects you've created to nil does nothing, since their variable declaration is in local scope - if you want the objects to be deallocated from memory you need to send them release before setting the pointer to the object to nil.
However, sending removeAllObjects is affecting your original sharedArray, because you didn't copy the array, you simply set a new pointer to point to the 'singleton'. You probably want this:
NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:sharedMutableArray];
You won't need to use removeAllObjects in the above case because it will be autorelease'd. I suggest you read this.
tmpArray is a pointer, and it's initialized to point to the same mutable array that sharedMutableArray points to. For that reason, the line:
[tmpArray removeAllObjects];
will empty out the array, and anyone using sharedMutableArray will see that change. In other words, the assignment
NSMutableArray *tmpArray = sharedMutableArray;
doesn't make a copy of the array itself, it only copies the pointer. Any messages you send using that pointer will go to the shared array. Likewise, assigning nil to tmpArray sets the pointer tmpArray, but doesn't do anything to the array itself.
Finally, setting a variable to nil never releases memory. Setting a property to nil, on the other hand, will release memory under some conditions (e.g. when the property is declared to retain its contents). You're setting a variable here, not a property, so there's no chance that the array will be released.

Can I reuse my pointer after it's been added to a mutable array?

Let's say I've got an array with strings.
NSArray *names = [NSArray arrayWithObjects: #"One", #"Two", #"Three", nil];
What I want is to initiate objects of some custom class and them add them to a mutable array. I'm using a custom init method that takes a string argument.
To be more specific, I want to [SomeClass alloc] initWithName: aName] and add the resulting object to a NSMutableArray.
I'm thinking of using Objective-C fast enumeration. So what I get is:
NSMutableArray *objects = [NSMutableArray arrayWithCapacity: [names count];
for (NSString *name in names) {
[objects addObject: [[[SomeClass alloc] initWithName: name] autorelease]];
}
The problem is that I can't add nil to the array and I don't like exception handling. However, my initiation method may return nil. So I decide to check first before adding (prevention). My new for-in-loop is:
SomeClass *someObject;
for (NSString *name in names) {
someObject = [[[SomeClass alloc] initWithName: name] autorelease];
if (someObject) {
[objects addObject: someObject];
}
}
Now, instead of immediately passing the new object to the array, I'm setting up a pointer someObject first and then passing the pointer to the array instead.
This example raises a question to me. When I someObject = [[[SomeClass alloc] initWithName: name] autorelease] in the loop, do the existing objects (which are added using the same pointer) in the array change too?
To put it in other words: does the addObject: (id)someObject method make a new internal copy of the pointer I pass or do I have to create a copy of the pointer — I don't know how — and pass the copy myself?
Thanks a lot! :-)
It's fine to reuse someObject; if you think about it, you're already reusing name each time you go through the loop.
-addObject: may or may not copy the object that you pass in. (It doesn't -- it retains the object rather than copying it, but it's conceivable that some NSMutableArray subclass could copy instead.) The important thing is that this code really shouldn't care about what -addObject: does.
Also, don't lose sight of the distinction between a pointer and the object that it points to. Pointers are just references, and a pointer is copied each time you pass it into a method or function. (Like C, Objective-C passes parameters by value, so passing a pointer into a method results in putting the value of the pointer on the stack.) The object itself isn't copied, however.
Short answer: no, you don't have to worry about reusing someObject.
Slightly longer answer: the assignment—someObject = ... assigns a new pointer value to the someObject variable; addObject: is then getting that value, not the address of someObject itself.
I think you're getting confused in the concept of pointer here. When you say someObject = [[[SomeClass alloc] init... you are basically pointing the someObject pointer to a new object. So to answer your question- your current code is fine.
As for whether arrays maintain copies of the objects added to them - NO, the array retains the object you add to it. However, that doesn't matter to your code above.
Three20 provides the answer!

simple NSMutable array question

umm So simple question here:
I have an instance of NSMutableArray declared in my header
NSMutableArray *day19;
#property (nonatomic, retain) NSMutableArray *day19
implementation:
#synthesize day19;
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Super basic I know just must be a confused morning or something...
thanks for any help
Is day19 actually an instance variable? In the snippet, it's not clear when it's declared as an instance variable or just as a variable outside the scope of the class.
A couple of things:
Are you sure viewDidLoad is the right place to init your array? Confer here.
Also, at least from the code you've got posted, it looks like you're being sloppy with your retains. If your property is a retain type, you should not be writing:
self.myProperty = [[Something alloc] init]; // double retain here, bad
You should instead be writing something like:
self.myProperty = [[[Something alloc] init] autorelease]; // single, good
Also, with
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
unless you have a
[newObject release];
down the pike, you've got a memory leak.
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Let me guess: You checked the array with code like this:
NSLog(#"day19 contains %lu objects", [day19 count]);
Remember that a message to nil does nothing and returns nil, 0, or 0.0. That's why the output said 0 objects: You don't have an array in the first place. The most probable reason for that is that viewDidLoad hasn't been called yet, so you have not yet created the mutable array.
It's also possible that you have an array (i.e., the view has been loaded) at the time you examine the array, but you didn't have an array yet (the view hadn't been loaded yet) at the time you tried to add to the array, so your addObject: message fell on deaf ears.
Consider creating the array earlier. You probably should be creating it in init or initWithCoder:.
A third possibility is that you examined the array before you ever added to it. Make sure you log or break at both points, so you know which one happened first.
Whatever the problem is, you also need to either assign the array to the instance variable, not the property, or autorelease the array before assigning it to the property. Otherwise, you're over-retaining the array, which means you will probably leak it later on. You probably need to review the Memory Management Programming Guide for Cocoa.