Objective C Memory Management Confusion - objective-c

I was reading the apple documentation for memory management, and came across something that I just don't understand. Basically, I don't understand why one does not need need to retain an instance variable through the "getter" method. I wrote this little program to see what would happen. I thought there would be a crash, but I am obviously missing something.
// main.m
// Test
//
#import <Foundation/Foundation.h>
#import "Test.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
//Initialize the test object
Test *t = [[Test alloc] init];
//Set the value to 5
[t setMyNum:[NSNumber numberWithInt:5]];
//Save a temp number that points to the original number
NSNumber *tempNum = [t myNum];
//release old number and retain new
[t setMyNum:[NSNumber numberWithInt:7]];
//Shouldn't this crash because tempNum is pointing to a deallocated NSNumber???
NSLog(#"the number is %#",tempNum);
[p drain];
return 0;
}
Doesn't tempNum point to a deallocated object??
All help is appreciated.
EDIT
This is the code in the getter and setter methods
#import "Test.h"
#implementation Test
- (void)setMyNum:(NSNumber *)newNum {
[newNum retain];
[myNum release];
myNum = newNum;
}
-(NSNumber *)myNum {
return myNum;
}
#end
As you can see I am calling release on the old object.
EDIT
It was suggested, and I thought rightfully so that the reason the tempNum is still around is because it hadn't been autoreleased from the pool yet. But even after moving the [pool drain] to right before the NSLog message, there is not crash??? Weird.

Since you are not explicitly releasing any objects, nothing is being deallocated until the autorelease pool is allowed to drain. Try inserting [p drain] before the last NSLog call. It should crash the NSLog call.
Additionally, if you are not retaining the NSNumber in your setMyNum: method, you will find that it will crash if you add [p drain] before tempNum is assigned.
To clarify the original question, calling a getter method doesn't (and shouldn't) necessarily imply that the caller wants to take ownership (i.e. retain) the variable. If that was the case, this code would leak:
NSLog("Number is %#", [t myNum]);
Also, it appears that NSNumber has an optimization whereby for small numbers, they cache the NSNumber objects, retain an extra copy, and return that version. So for small constants, [NSNumber numberWithInt: N] will return an object with 2 reference counts (available via [theNumber retainCount]). To explicitly see what happens, use a larger constant in the program, an NSNumber will retain a 'fresh' object with a reference count of 1 (that will also be autoreleased).

#import "Test.h"
#implementation Test
- (void)setMyNum:(NSNumber *)newNum
{
[newNum retain];
[myNum release];
myNum = newNum;
}
-(NSNumber *)myNum
{
return myNum;
}
#end
Here in the setter method [myNum release] which releases the mynum, but then we are again giving some new value that is newnum, hence from the getter method the temporary number gets the number which has not been deallocated till the [p drain] so there will not be any crash.

#import "Test.h"
#implementation Test
(void)setMyNum:(NSNumber *)newNum
{
[newNum retain];
[myNum release];
myNum = newNum;
}
(NSNumber *)myNum
{
return myNum;
}
#end
Here is the setter method [myNum release]; Which releases the myNum, but then we are again giving some new value that is newNum, hence from the getter method the temporary number gets the number which has not been deallocated till the [p drain]; so there will not be any crash. Even if the following code will not crash as there is autorelease pool but no autorelease method.
[t setMyNum:[NSNumber numberWithInt:70]];
So releasing the pool will not deallocate the number.

Related

debugging objective c memory leak with xCode Leaks

I'm doing my first steps in finding memory leaks in xCode 4.5 and using the Leaks instrument. I found a couple of issues and seemed to fix them, but this one eludes me.
Here is the code:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = nm;
[imgInfo->name retain]; // I'm using it outside of this method
Leaks reports a leak in the second line, with the percentage next to the "i" at %100.
So I tried two things:
One, I marked nm with autohrleas like this:
NSString *nm = [[NSString stringWithUTF8String:img->name.c_str()] autorelease];
Two, I also tried calling release on nm after it's assignment to imgInfo->name so the code looks like this:
imgInfo->name = nm;
[imgInfo->name retain];
[nm release];
But in both cases the app crashes with BAD_ACCESS when I run it, and call [imgInfo->name UTF8String].
What am I missing?
EDIT following Rob's answer:
This is the RUBEImageInfo class:
#import "cocos2d.h"
#interface RUBEImageInfo : NSObject {
#public CCSprite* sprite; // the image
#public NSString* name; // the file the image was loaded from
#public class b2Body* body; // the body this image is attached to (can be NULL)
#public float scale; // a scale of 1 means the image is 1 physics unit high
#public float angle; // 'local angle' - relative to the angle of the body
#public CGPoint center; // 'local center' - relative to the position of the body
#public float opacity; // 0 - 1
#public bool flip; // horizontal flip
#public int colorTint[4]; // 0 - 255 RGBA values
}
#end
And the .m:
#import "RUBEImageInfo.h"
#implementation RUBEImageInfo
// Nothing much to see here. Just make sure the body starts as NULL.
-(id)init
{
if( (self=[super init])) {
body = NULL;
}
return self;
}
-(void) dealloc {
[name release];
[super dealloc];
}
#end
A couple of reactions:
Instruments identified where the leaked object was allocated, but in this case, this code might not be the source of the leak. You should:
ensure you release the name in the dealloc method of RUBEImageInfo; and
also, if you're setting name a second time, make sure you release the previous name object before you set it to a new object.
Your life will be much easier if you use declared properties rather than dereferencing class instance variables. For example, if name was declared as:
#property (nonatomic, copy) NSString *name; // you could use `retain`, too, but `copy` is safer when dealing with strings
Then you would set the name property as so:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo.name = nm;
// this is no longer needed as the `name` setter will take care of memory semantics
// [imgInfo->name retain]; // I'm using it outside of this method
By using the setter accessor method (i.e. the "dot syntax" of imgInfo.name), it will take care of a lot of routine memory semantics of releasing any previous object that name may have referenced, and it will do the necessary copy or retain. Obviously, the RUBEImageInfo method dealloc still needs to release name, but at least it simplifies the memory semantics of the name property of RUBEImageInfo objects.
Since you are using manual reference counting, I'd encourage you to investigate the "static analyzer" (invoked by selecting "Analyze" from Xcode's "Product" menu). The Leaks tool in Instruments will tell you what leaked, but it doesn't tell you where the leak happened; it has no way of knowing; it can only show you where the leaked object was allocated and you'll have to hunt down the logic error yourself. The static analyzer can sometimes point out errors that lead to leaks, but more importantly, show you where the leak was caused, rather than just where the leaked object was originally instantiated. You should have a clean bill of health from the static analyzer before you even bother running Instruments.
Looking at your code sample, if you're not going to use declared properties (not sure why you wouldn't, as it makes life easier, but to each his own), I'd suggest making sure you initialize all of your objects in init and release all of them in dealloc:
#implementation RUBEImageInfo
-(id)init
{
if ((self=[super init])) {
body = NULL;
name = nil;
sprite = nil;
// I might initialize other class instance variables here, too, but that's up to you
}
return self;
}
-(void) dealloc {
[name release];
// shouldn't you release `body` and `sprite`, too?
[super dealloc];
}
#end
Then your code that sets the name instance variable would make sure to release the previous object before setting the new object. Thus the initial instantiation might look like:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = [nm retain]; // retain the new object
But if you update it later, you should:
NSString *nm = [NSString stringWithUTF8String:someNewImg->name.c_str()];
[imageInfo->name release]; // release the old one
imgInfo->name = [nm retain]; // retain the new object

is it allowed to call [obj copy] in ObjC with ARC?

There's one thing I don't understand regarding ARC: how should we now treat local variables that were created using [... copy]? If I make a property with (copy) flag, ARC will handle this automatically, but as far as I know there's no __copy flag for variables.
I've tested this with such code:
#interface Foo : NSString
#end
#implementation Foo
- (void) dealloc {
NSLog(#"%p deallocated", self);
}
- (NSUInteger) length {
return 1;
}
- (unichar) characterAtIndex: (NSUInteger) i {
return 'x';
}
#end
- (void) foo {
Foo *f = [[Foo alloc] init];
NSLog(#"%p", f);
Foo *f2 = [f copy];
NSLog(#"%p", f2);
}
What I get is:
0x102406530
0x102015f10
0x102406530 deallocated
I never get "0x102015f10 deallocated", which would suggest the copied variable doesn't get released. It doesn't even get autoreleased, because when I made another method [Foo foo] that returned an autoreleased object, I did get a "deallocated" message a moment later.
So is there any way I can cause it to be released without converting it to a property?
Ok, my bad - ARC does actually handle copied objects properly. I got wrong results because of using NSString for the test, because I wanted to use a class that already implemented copying instead of implementing it explicitly; when I repeated the test on a class inheriting from NSObject and implementing copyWithZone: by returning [[Foo alloc] init], I got two "deallocated" messages. Thanks to #Paul.s for pointing that out.

Object existing after release

Can anyone explain to me why class object still exist after release. Here is the code
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyClass *class = [[MyClass alloc] init];
NSLog(#"%#", [class showMouse]);
NSLog(#"%#", [class printKbd]);
[class release];
NSLog(#"%#", [class printKbd]);
//still exist
[pool drain];
return 0;
}
Actually, dealloc does get called, you can check it by adding NSLog(#"dealloc called") inside dealloc method of MyClass.
Why does it still work then? When an object gets released, the memory is not zeroed, it's simply marked as free to use by system. As a result, the code may still exist at the address of the pointer and *class is simply a pointer to a block of memory. Here's the great SO answer that explains it in details.
Important thing to note is, should the program execution last any longer, the call to [class printKbd] would most likely crash. That's why it's important to assign nil to pointer, just to make sure we won't access the undefined part of memory.

Getting error when added NSNumber to an array

When my program gets to the line:
[userNumSequence addObject:[NSNumber numberWithInteger: sequenceNumber]];
it gets the error:
Program received signal: “EXC_BAD_ACCESS”.
All I'm wanting to do is to store an integer in the array.
// JBNumberGeneration.m
#import "JBNumberGeneration.h"
#implementation JBNumberGeneration
- (id) init{
if (self = [super init]){
userNumSequence = [NSMutableArray arrayWithCapacity:0];
} return self;
}
-(IBAction)logSequenceNumber:(id)sender{
NSString *titleOfButton = [sender title];
int sequenceNumber = [titleOfButton integerValue];
i=0;
[userNumSequence addObject:[NSNumber numberWithInteger: sequenceNumber]];
//int currentNum = [((NSNumber*)[userNumSequence objectAtIndex: i]) integerValue];
//NSLog(#"%i", currentNum);
int count = [userNumSequence count];
NSLog(#"Array size: %i", count);
i++;
}
#end
// JBNumberGeneration.h
#import <Cocoa/Cocoa.h>
#interface JBNumberGeneration : NSObject {
IBOutlet NSTextField *displayLabel;
int randNum;
int level;
int i;
NSMutableArray* userNumSequence;
}
-(IBAction)logSequenceNumber:(id)sender;
#end
EXC_BAD_ACCESS usually occurs when you try to access a member that has already been deallocated. Because you are calling [NSMutableArray arrayWithCapacity:] in your init function, it may have already been released by the time logSequenceNumber:(id)sender is called. Try adding #property (nonatomic, retain) NSMutableArray* userNumSequence to your #interface and #synthesize userNumSequence to your #implementation. Then call self.userNumSequence = [NSMutableArray arrayWithCapacity:0] in your init method. Don't forget to set it to nil in dealloc.
EDIT: Also, just to be clear the Cocoa memory management naming standards are like this:
If you call [[Object alloc] initSomehow], or [object retain] you are responsible for releasing it (calling init methods will automatically call retain).
If you call methods like [Object objectWithSomething:something], these are usually autoreleased and will be released sometime in the future. You should never assume these exist beyond the scope in with they are created. According to the Cocoa documentation, scope includes the call stack. If a: calls b: which calls c:, and c: returns an autoreleased object, it can be passed safely all the way back up for a: to use. Beyond that it is released. This is at least my interpretation of the explanation of autorelease.
If you need to use something for the lifetime of your object, retain it when you get it and release it in dealloc.

Array Via Setter?

This is just a test to help me learn Objective-C, it uses NSMutableArray to add tire objects to an instance variable in a car object:
// INTERFACE
#interface CarBody : NSObject {
NSMutableArray *tires;
}
// Should this be (id *) it works but I was convinced it would be pointer?
- (void) addTire:(id)newTire;
#end
#interface TireSnow : NSObject {
}
#end
// IMPLEMENTATION
#implementation CarBody
- (void) addTire:(id)newTire {
[tires addObject:newTire];
// ** Release here or in main()?
}
- (id) init {
[super init];
tires = [[NSMutableArray alloc] init];
NSLog(#"_init: %#", NSStringFromClass([self class]));
return self;
}
- (void) dealloc {
NSLog(#"_deal: %#", NSStringFromClass([self class]));
[tires release];
[super dealloc];
}
#end
I do have a few questions ...
In the addTire method, is the (id) right, I thought it was going to be (id *)
Releasing the item I am adding to the array, should I do it inside the setter or in main() after I call it?
Am I allocating / releasing the NSMutableArray (tires) in the right place, it feels right?
Is there a way to do this with NSArray (as I only want 4 tires), I did try this but got mixed up trying to alloc the array and define its size.
thanks in advance for any help ...
gary
EDIT:
I am reading the memory management rules, but they do take some time to absorb and do require a certain level of understanding that is difficult to gain when starting out. What I am wondering about in this situation is where would I release the newSnowTire that I alloc in main. When I add it to the array in the setter does that create a new object in the array (thats my understanding) so my thinking was that I would need to release the instance I got from alloc?
// MAIN
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CarBody *newCarBody_001;
TireSnow *newSnowTire_001;
newCarBody_001 = [[CarBody alloc] init];
newSnowTire_001 = [[TireSnow alloc] init];
[newCarBody_001 addTire:newSnowTire_001];
// Clean up
[newCarBody_001 release];
[newSnowTire_001 release];
[pool drain];
return 0;
}
EDIT_002:
Just added the code to generate all 4 tires with the tire release moved into the loop after the setter is called.
// CREATE TIRES
for(int loopCounter=0; loopCounter<4; loopCounter++) {
newSnowTire_001 = [[TireSnow alloc] init];
[newCarBody_001 addTire:newSnowTire_001];
[newSnowTire_001 release];
}
I just checked this and it is correct ...
NewSnowTire_001 (alloc) RetainCount = 1
NewSnowTire_001 (addTire) RetainCount = 2
NewSnowTire_001 (release) RetainCount = 1
NewSnowTire_001 Finally Released by dealloc method.
(id) or (TireSnow*) is similar, I had problems with understanding this in the beginning too. So basically an object is of a pointer type (kind of), but the id is already a pointer, so you don't need a * after it.
In main. Releasing should happen in the same place as the alloc/retain/copy.
Seems okay to me.
You can use [[NSMutableArray alloc] initWithCapacity:4]. This is only a hint to the array, it will automatically expand if you insert more items. Check [tires length] in the addTire method.
Your -init should look more like this:
-(id)init
{
if (self = [super init]) {
// init here
}
return self;
}
This allows self to be nil if something breaks in the init-chain.
You should use id (not id*). Objective-C do not have a concept of a root object as you have in for example Java, where java.lang.Object is the root class for any and all classes. Cocoa adds two root classes (classes without a super class) named NSObject, and less common NSProxy. id is a pointer to any object regardless of super class.
It is unfortunate that id, and also Class, are defined as a pointers, which means they are the only places where you should not add the '*' character when defining references. An unfortunate legacy from the old days.
Release in main, you should always release objects int he same scope that you create or retain them. The addTire: method is exceptionally god example of this, never release objects that has been handed to you as an argument. Only release objects handed to you as a result (And even then only from the alloc, new and copy method).
The allocation and release of the instance variable tires is a schoolbook example of where it should be done. I would expand the init to check for the super class result, as this though (Never trust super to always work, or even return the same instance):
- (id) init {
self = [super init];
if (self) {
tires = [[NSMutableArray alloc] init];
NSLog(#"_init: %#", NSStringFromClass([self class]));
}
return self;
}
You can use NSArray if you have access to all four tires from the start. Best way would probably be to require the tires in the init method. If that is not a possibility then you have nothing to gain from using an NSArray over a NSMutableArray.
The type id is defined like this (in objc.h):
typedef struct objc_object {
Class isa;
} *id;
So id is already a pointer to an object. An id* would be a pointer to a pointer.
As for where you should release the tire — there's nothing in the code you posted that shows a need to release it at all. That object never claims ownership of the tire, so it has no need to release it. If something claimed ownership of the tire somewhere else in your code, then that object has a responsibility to release its claim when it's finished.
This is explained in the Objective-C memory management rules. It's pretty short and a must-read.