Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 07-26-2009, 07:51 PM   #1 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default Memory Management / Releasing Objects

Im having problem with memory management problem, my app runs smoothly on the simulator, but it often crashes on my device.

I just want to know if there are some guidelines of when to release an object.

What i understand is
if something starts with alloc, you need to release it.
like
Code:
NSString *string = [[NSString alloc] init];
and if the object started with initxxxxx need to have autorelease
Code:
NSString *string = [[NSString initwithformat:@"123"] autorelease];
everything delcare in @synthesize, needs to be in - (void)dealloc.

I have declare an object inside a for loop, but when i tried to release it, it crashes.

What are the situation that we must release the object on?

Correct me if im wrong, thanks.

and what are the best way to code and to make sure keep everything in low memory?!

option 1:
Code:
NSString *string = [[NSString alloc] init];
self.stringIWant = string;
[release string];
option 2:
Code:
self.stringIWant = [[NSString alloc] init];

Last edited by svveet; 07-26-2009 at 07:56 PM.
svveet is offline   Reply With Quote
Old 07-26-2009, 08:01 PM   #2 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

There aren't too many cases where you HAVE to autorelease. In fact, due to the limited resources available on the iPhone, you want to avoid autoreleasing as much as possible.

Generally speaking, your variables should have a 3-step life.
  1. Creation. Ex: NSString *myString = [[NSString alloc] init];
  2. Use. Ex: [[cell textLabel] setText: myString];
  3. Release: Ex: [myString release], myString = nil;

As long as you do the release before you hit the last } in your method (or loop, depends on where you created it), you should be fine.

Other than that, I'd say that the rest of what you said is generally correct. You would need to post some specific examples of where you are crashing in order to get better help.



Edit:
Option 1 is correct (well, that may not be the best initialization example, since the string really doesn't have a value, but you get the idea). Option 2 is a leak.

IMO, do yourself a favor and avoid dot-syntax. Ex:

[self setStringIWant: string];
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 08:48 PM   #3 (permalink)
high school developer
 
Join Date: Jul 2009
Posts: 63
Default

One of the things that I have found is that on the device it may crash because of a low-memory warning. You do not get these crashes in the simulator because your computer lets programs use more than 20MBs of RAM. One of the ways to avoid these crashes is to respond to the didReceiveMemoryWarning method. In this method you should release anything that you are not using so that the program doesn't crash. IMPORTANT: If you do use this method, do NOT use the normal "release" command on whatever you need to release! This can lead to it crashing because of it releasing an object more than once. The memory warning method can be called more than once in an app's lifecycle. Releasing an object that has already been released will crash your app. To combat this, instead of using [myObject release]; use myObject = nil;. This is very important and can be a pain to debug later on (I know the hard way).

Hope this helps! If there was anything that was not clear, feel free to ask and I will try to clarify.
anonymous is offline   Reply With Quote
Old 07-26-2009, 08:52 PM   #4 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Here is one of the example where im trying to read a file from my sandbox directory, when i try to release pathToDefaultPlist and documentsDirectory, it crashes. (trying to release all)
whats the correct release in this situation.
Code:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
	
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
	
NSString *fileName = [[NSString alloc] initWithFormat:@"%@.plist", kMyTrackListFileName]; 
    //self.pathToUserCopyOfPlist = [documentsDirectory stringByAppendingPathComponent:fileName];
	[self setPathToUserCopyOfPlist:[documentsDirectory stringByAppendingPathComponent:fileName]];
    
if ([fileManager fileExistsAtPath:pathToUserCopyOfPlist] == NO) 
	{
     NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:kMyTrackListFileName ofType:@"plist"];
        if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:pathToUserCopyOfPlist error:&error] == NO) 
		{
            NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
        }
    }
[fileNameArray release];
[fileName release];

another example:
Code:
	UIImage *shoppingkartImage = [UIImage imageNamed:@"shoppingkart.png"];
	UIBarButtonItem *shoppinglistButton = [[UIBarButtonItem alloc] initWithImage:shoppingkartImage style:UIBarButtonItemStyleBordered 
target:self
action:@selector(showShoppingList)];
	self.navigationItem.leftBarButtonItem = shoppinglistButton;
	[shoppinglistButton release];
when i release shoppingkartImage, it crashes.
do i need to release uiimage?

and do we release NSUInteger and Int object?
svveet is offline   Reply With Quote
Old 07-26-2009, 08:56 PM   #5 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Quote:
Originally Posted by anonymous View Post
One of the things that I have found is that on the device it may crash because of a low-memory warning. You do not get these crashes in the simulator because your computer lets programs use more than 20MBs of RAM. One of the ways to avoid these crashes is to respond to the didReceiveMemoryWarning method. In this method you should release anything that you are not using so that the program doesn't crash. IMPORTANT: If you do use this method, do NOT use the normal "release" command on whatever you need to release! This can lead to it crashing because of it releasing an object more than once. The memory warning method can be called more than once in an app's lifecycle. Releasing an object that has already been released will crash your app. To combat this, instead of using [myObject release]; use myObject = nil;. This is very important and can be a pain to debug later on (I know the hard way).

Hope this helps! If there was anything that was not clear, feel free to ask and I will try to clarify.
so what you do is set everything to nil inside the mothods?
and in didReceiveMemoryWarning
do the following code
Code:
[stringA release];
[stringB release];
is this right?
svveet is offline   Reply With Quote
Old 07-26-2009, 08:56 PM   #6 (permalink)
high school developer
 
Join Date: Jul 2009
Posts: 63
Default

Only release it if it was made with alloc and init. If its just like NSString *mySTR = [NSString stringWithFormat:@"Hello World %f", myFloat]; Then you do NOT need to release it and if you do then it WILL crash.
anonymous is offline   Reply With Quote
Old 07-26-2009, 08:58 PM   #7 (permalink)
high school developer
 
Join Date: Jul 2009
Posts: 63
Default

Quote:
Originally Posted by svveet View Post
so what you do is set everything to nil inside the mothods?
and in didReceiveMemoryWarning
do the following code
Code:
[stringA release];
[stringB release];
is this right?
No you actually have it backwards. You can use release in other methods but in didReceiveMemoryWarning only use object=nil;.
anonymous is offline   Reply With Quote
Old 07-26-2009, 08:58 PM   #8 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by anonymous View Post
Releasing an object that has already been released will crash your app. To combat this, instead of using [myObject release]; use myObject = nil;
I'm 99% certain this is a leak. Assigning nil is not the same thing as releasing. Take the combo approach:

Code:
[myObject release], myObject = nil;
So, you honor the rules of memory management by releasing the object, and you avoid crashes later by assigning to nil, since sending a message to nil doesn't actually do anything.

Now, if you're talking about a property, that's different. In that case:

Code:
[self setMyProperty: nil];
...is perfectly acceptable, since the property will release the old value.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:00 PM   #9 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by anonymous View Post
Only release it if it was made with alloc and init. If its just like NSString *mySTR = [NSString stringWithFormat:@"Hello World %f", myFloat]; Then you do NOT need to release it and if you do then it WILL crash.
True, but this creates an auto-released object. See my first post in this thread.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:02 PM   #10 (permalink)
high school developer
 
Join Date: Jul 2009
Posts: 63
Default

Quote:
Originally Posted by BrianSlick View Post
I'm 99% certain this is a leak. Assigning nil is not the same thing as releasing. Take the combo approach:

Code:
[myObject release], myObject = nil;
So, you honor the rules of memory management by releasing the object, and you avoid crashes later by assigning to nil, since sending a message to nil doesn't actually do anything.

Now, if you're talking about a property, that's different. In that case:

Code:
[self setMyProperty: nil];
...is perfectly acceptable, since the property will release the old value.
Ok that makes sense. So in the didReceiveMemoryWarning method, you should just do if(myObject!=nil) [myObject release];
That way it won't release something more than once but it will actually get released.
anonymous is offline   Reply With Quote
Old 07-26-2009, 09:09 PM   #11 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Quote:
Originally Posted by anonymous View Post
Only release it if it was made with alloc and init. If its just like NSString *mySTR = [NSString stringWithFormat:@"Hello World %f", myFloat]; Then you do NOT need to release it and if you do then it WILL crash.
I see.
so these i dont need to release any of these?!

Code:
NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:kMyTrackListFileName ofType:@"plist"];

UIImage *shoppingkartImage = [UIImage imageNamed:@"shoppingkart.png"];

NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
svveet is offline   Reply With Quote
Old 07-26-2009, 09:12 PM   #12 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by svveet View Post
Here is one of the example where im trying to read a file from my sandbox directory, when i try to release pathToDefaultPlist and documentsDirectory, it crashes. (trying to release all)
whats the correct release in this situation.
Code:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
	
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
	
NSString *fileName = [[NSString alloc] initWithFormat:@"%@.plist", kMyTrackListFileName]; 
    //self.pathToUserCopyOfPlist = [documentsDirectory stringByAppendingPathComponent:fileName];
	[self setPathToUserCopyOfPlist:[documentsDirectory stringByAppendingPathComponent:fileName]];
    
if ([fileManager fileExistsAtPath:pathToUserCopyOfPlist] == NO) 
	{
     NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:kMyTrackListFileName ofType:@"plist"];
        if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:pathToUserCopyOfPlist error:&error] == NO) 
		{
            NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
        }
    }
[fileNameArray release];
[fileName release];
Where did fileNameArray come from? That's the only issue I see.

Quote:
Originally Posted by svveet View Post
another example:
Code:
	UIImage *shoppingkartImage = [UIImage imageNamed:@"shoppingkart.png"];
	UIBarButtonItem *shoppinglistButton = [[UIBarButtonItem alloc] initWithImage:shoppingkartImage style:UIBarButtonItemStyleBordered 
target:self
action:@selector(showShoppingList)];
	self.navigationItem.leftBarButtonItem = shoppinglistButton;
	[shoppinglistButton release];
when i release shoppingkartImage, it crashes.
do i need to release uiimage?
shoppingKartImage is an autoreleased object, therefore you should not release it. However, as stated previously, you want to avoid autoreleased objects. If it is a small image, and for a nav button I assume it is, I probably wouldn't worry too much about it. If it becomes an issue, go more of an alloc/init route, perhaps with initWithContentsOfFile:, and then manually release.

Quote:
Originally Posted by svveet View Post
and do we release NSUInteger and Int object?
Those are primitives, not objects. Therefore, do not release. A decent rule of thumb is if there is a * involved - ex: NSString *myString, UIImage *myImage - it is an object, and if you alloc/init'ed it, you need to release it. ints, floats, doubles, CGFloats, etc don't have the *, are not objects, so you don't.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:18 PM   #13 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Quote:
Originally Posted by BrianSlick View Post
Where did fileNameArray come from? That's the only issue I see.
Code:
NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
	
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
	
	NSString *fileName = [[NSString alloc] initWithFormat:@"%@.plist", kMyTrackListFileName]; 
    //self.pathToUserCopyOfPlist = [documentsDirectory stringByAppendingPathComponent:fileName];
	[self setPathToUserCopyOfPlist:[documentsDirectory stringByAppendingPathComponent:fileName]];
    
	if ([fileManager fileExistsAtPath:pathToUserCopyOfPlist] == NO) 
	{
        NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:kMyTrackListFileName ofType:@"plist"];
        if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:pathToUserCopyOfPlist error:&error] == NO) 
		{
            NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
        }
    }
	
	NSMutableArray *fileNameArray = [[NSMutableArray alloc] initWithContentsOfFile:pathToUserCopyOfPlist];
	[self setMyTrackListData:fileNameArray];
	//self.myTrackListData = fileNameArray;
	[fileNameArray release];
	[fileName release];
forgot to put in that line at the end, i was trying to release documentsDirectory before. i guess i dont need to release that now.


Quote:
Originally Posted by BrianSlick View Post
Those are primitives, not objects. Therefore, do not release. A decent rule of thumb is if there is a * involved - ex: NSString *myString, UIImage *myImage - it is an object, and if you alloc/init'ed it, you need to release it. ints, floats, doubles, CGFloats, etc don't have the *, are not objects, so you don't.
I see, thanks very much for the explanation.
svveet is offline   Reply With Quote
Old 07-26-2009, 09:18 PM   #14 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by anonymous View Post
Ok that makes sense. So in the didReceiveMemoryWarning method, you should just do if(myObject!=nil) [myObject release];
That way it won't release something more than once but it will actually get released.
No. If you are in the memory warning method, I'm assuming we're dealing with properties here. In which case, do exactly what I said before:

Code:
[self setMyObject: nil];
The property will release the old value, so you're good there. The property is now nil, so by the time you get to dealloc, and the release message is sent again, it is sending to nil, which doesn't have any effect.

Besides, you shouldn't automatically clear out all of your properties in this method. If you have things you don't need, sure, clear them out. But if the program is still actively using them, then clearing out the properties could cause a whole different set of problems. For example, if you have retained any detail view controllers for repeated use, this would be a good place to clear them out. But don't clear out the array that is driving your table view. Do save your data and brace for impact, however.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:25 PM   #15 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by svveet View Post
I see.
so these i dont need to release any of these?!
Correct.

Quote:
Originally Posted by svveet View Post
forgot to put in that line at the end, i was trying to release documentsDirectory before. i guess i dont need to release that now.
Also correct.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:32 PM   #16 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

I have just tested my leaks on instrument, fixed up my leaks now, thanks to you two.

does any of you know what "GeneralBlock-488", "GeneralBlock-80", etc means in Instrument?
svveet is offline   Reply With Quote
Old 07-26-2009, 09:33 PM   #17 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by svveet View Post
I have just tested my leaks on instrument, fixed up my leaks now, thanks to you two.

does any of you know what "GeneralBlock-488", "GeneralBlock-80", etc means in Instrument?
Could be pretty much anything, AFAIK. Hard to track down.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 09:40 PM   #18 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

I have another warning message inside my xcode.

Im trying to call a function inside the same class, for example:

Code:
// i want to call functionA to do stuff
[self functionA];
it gives me an warning saying "Warning, may not respond to functionA".
it doesnt stop me from building the app, but one of my other friend told me that i shouldnt have this kind of warning at all.

is there a better way to code this?
svveet is offline   Reply With Quote
Old 07-26-2009, 09:42 PM   #19 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Quote:
Originally Posted by svveet View Post
I have another warning message inside my xcode.

Im trying to call a function inside the same class, for example:

Code:
// i want to call functionA to do stuff
[self functionA];
it gives me an warning saying "Warning, may not respond to functionA".
it doesnt stop me from building the app, but one of my other friend told me that i shouldnt have this kind of warning at all.

is there a better way to code this?
You need to declare it in your header file. Ex:

Code:
- (void)functionA;
And your friend is correct. Pretend that warnings are actually errors, and fix them.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 10:04 PM   #20 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

sweet, ive fixed it.

Here is another problem i have found.
when i try to release "trackDictionary", it crashes.

Code:
int stringlength = [self.trackFileName length];
		NSString *trimmedFileName = [trackFileName substringToIndex:stringlength-6];
				
		// get the location of application sandbox
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
		NSString *documentsDirectory = [paths objectAtIndex:0];
		
		NSString *finalFileName = [[NSString alloc] initWithFormat:@"%@.plist", trimmedFileName];
		NSString *pathToPlist = [documentsDirectory stringByAppendingPathComponent:finalFileName];
		self.pathToCurrentTrackPlist = pathToPlist;

		// Check for data in Documents directory. Copy default appData.plist to Documents if not found.
		NSFileManager *fileManager = [NSFileManager defaultManager];
		NSError *error;
		if ([fileManager fileExistsAtPath:pathToPlist] == NO) 
		{
			NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:trimmedFileName ofType:@"plist"];
			if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:pathToPlist error:&error] == NO) 	
			{
				NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
			}
		}
		
		// store the track dictionary into trackdictionary
		NSMutableDictionary *trackDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:pathToPlist];
		[self setTrackDict:trackDictionary];
		//[trackDictionary release];
		[finalFileName release];
svveet is offline   Reply With Quote
Old 07-26-2009, 10:36 PM   #21 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Looks ok to me, but may I suggest a little reorganization that might help to keeps things straight. Remove red, add blue.

Code:
int stringlength = [self.trackFileName length];
NSString *trimmedFileName = [trackFileName substringToIndex:stringlength-6];
				
// get the location of application sandbox
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
		
NSString *finalFileName = [[NSString alloc] initWithFormat:@"%@.plist", trimmedFileName];
NSString *pathToPlist = [documentsDirectory stringByAppendingPathComponent:finalFileName];
self.pathToCurrentTrackPlist = pathToPlist;  // Avoid dot-syntax
[self setPathToCurrentTrackPlist: pathToPlist];
// You no longer have a need for pathToPlist.  You have populated the property; use it.

// Also, you are now done with finalFileName, so release it here.  Don't wait until later.
[finalFileName release], finalFileName = nil;

// Check for data in Documents directory. Copy default appData.plist to Documents if not found.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
if ([fileManager fileExistsAtPath:pathToPlist] == NO) 
if ([fileManager fileExistsAtPath:[self pathToCurrentTrackPlist]] == NO)
{
   NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:trimmedFileName ofType:@"plist"];
   if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:pathToPlist error:&error] == NO)
   if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:[self pathToCurrentTrackPlist] error:&error] == NO) 	
	{
		NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
	}
}
		
// store the track dictionary into trackdictionary
NSMutableDictionary *trackDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:pathToPlist];
NSMutableDictionary *trackDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:[self pathToCurrentTrackPlist]];
[self setTrackDict:trackDictionary];
//[trackDictionary release];
[finalFileName release];
This shouldn't be a crash, but if it really and truly is crashing here with the release, then we probably need to take a look at your property declaration for trackDict. Or, I think that initWithContentsOfFile might be intended for an NSArray, not sure. If so, you might need to do something like setArray:.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 11:07 PM   #22 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Quote:
Originally Posted by BrianSlick View Post
This shouldn't be a crash, but if it really and truly is crashing here with the release, then we probably need to take a look at your property declaration for trackDict. Or, I think that initWithContentsOfFile might be intended for an NSArray, not sure. If so, you might need to do something like setArray:.
Thanks for the fixing up, now i have learned more about cleaning up.

Here is the property list of my trackDict and yes, it still cause crash, only if i dont release the trackDict, it will be fine. but i know thats wrong.

Code:
NSMutableDictionary *trackDict;
@property (nonatomic, retain) NSMutableDictionary *trackDict;
is there another way to do this?
svveet is offline   Reply With Quote
Old 07-26-2009, 11:20 PM   #23 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Well, if there's a problem here, I'm just not seeing it.

Just for grins, maybe try this:

Code:
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:[self pathToCurrentTrackPlist]];
if ([self trackDict] == nil)
{
   NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
   [self setTractDict: tempDict];
   [tempDict release], tempDict = nil;
}
[[self trackDict] removeAllObjects];
[[self trackDict] addEntriesFromDictionary: dictionary];
[dictionary release], dictionary = nil;

If this doesn't work, I'm out of ideas.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
BrianSlick is offline   Reply With Quote
Old 07-26-2009, 11:27 PM   #24 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Australia
Posts: 180
Default

Quote:
Originally Posted by BrianSlick View Post
Well, if there's a problem here, I'm just not seeing it.

Just for grins, maybe try this:

Code:
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:[self pathToCurrentTrackPlist]];
if ([self trackDict] == nil)
{
   NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
   [self setTractDict: tempDict];
   [tempDict release], tempDict = nil;
}
[[self trackDict] removeAllObjects];
[[self trackDict] addEntriesFromDictionary: dictionary];
[dictionary release], dictionary = nil;

If this doesn't work, I'm out of ideas.

nope, still crashes when i click "back button" on the navigationcontroller

here the the whole code in that method

Code:
- (void)loadDictionaryFromFile {
	
	if ([self trackFileName] != nil) {
		// get the length of the filename, and cut the '.plist' off
		int stringlength = [self.trackFileName length];
		NSString *trimmedFileName = [trackFileName substringToIndex:stringlength-6];
				
		// get the location of application sandbox
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
		NSString *documentsDirectory = [paths objectAtIndex:0];
		
		NSString *finalFileName = [[NSString alloc] initWithFormat:@"%@.plist", trimmedFileName];
		NSString *pathToPlist = [documentsDirectory stringByAppendingPathComponent:finalFileName];
		[self setPathToCurrentTrackPlist:pathToPlist];
		
		[finalFileName release], finalFileName = nil;

		// Check for data in Documents directory. Copy default appData.plist to Documents if not found.
		NSFileManager *fileManager = [NSFileManager defaultManager];
		NSError *error;
		if ([fileManager fileExistsAtPath:[self pathToCurrentTrackPlist]] == NO) 
		{
			NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:trimmedFileName ofType:@"plist"];
			if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:[self pathToCurrentTrackPlist] error:&error] == NO) 	
			{
				NSAssert1(0, @"Failed to copy data with error message '%@'.", [error localizedDescription]);
			}
		}
		
		// store the track dictionary into trackdictionary
		NSMutableDictionary *trackDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:[self pathToCurrentTrackPlist]];
		[self setTrackDict:trackDictionary];
		//self.trackDict = trackDictionary;
		//[trackDictionary release];
		

		// declare array
		[self setFieldDataArray:[[NSMutableArray alloc] init]];
		[self setSectionArray:[[NSMutableArray alloc] init]];
		
		// name 
		NSString *trackName = [[self trackDict] objectForKey:kNameKey];
		if (trackName == nil) 
			trackName = @"";
		[[self fieldDataArray] addObject:trackName];
		[self setNameText:trackName];
		[trackName release];
		
		
		// date
		NSDate *theDate = [[self trackDict] objectForKey:kDateKey];
		[self setDateDate:theDate];
		NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
		[formatter setDateFormat:@"dd MMM yyyy"];
		NSString *trackDate = [formatter stringFromDate:theDate];
		NSString *finalDate = [[NSString alloc] initWithFormat:@"%@", trackDate];
		if (theDate == nil) 
			finalDate = @"";
		[[self fieldDataArray] addObject:finalDate];
		[formatter release];
		[finalDate release];
		
		
		// rating
		NSString *trackRating = [[self trackDict] objectForKey:kRatingKey];
		if (trackRating == nil) 
			trackRating = @"";
		[[self fieldDataArray] addObject:trackRating];
		ratingNum = [trackRating intValue];
		[[self sectionArray] addObject:@"detail"];
		
		// tag
		NSMutableArray *tagarray = [[self trackDict] objectForKey:kTagKey];
		tagCount = [tagarray count];
		NSLog(@"tagCount = %i", tagCount);
		NSMutableString *trackTag = [[NSMutableString alloc] init];
		
		if ([tagarray count] > 0 ) {
			for (int i = 0; i < [tagarray count]; i++) {
				[trackTag appendFormat:[tagarray objectAtIndex:i]];
				if (i == [tagarray count]-1) 
					[trackTag appendFormat:@""];
				else
					[trackTag appendFormat:@", "];
			}
		}else {
			trackTag = @"";
		}
		[[self fieldDataArray] addObject:trackTag];
		[self setTagText:trackTag];
		[trackTag release];
		if (tagCount > 0)
			[[self sectionArray] addObject:@"tag"];

		
		// item
		NSMutableArray *itemarray = [[self trackDict] objectForKey:kItemKey];
		itemCount = [itemarray count];
		NSLog(@"itemcount = %i", itemCount);
		NSMutableString *trackItem = [[NSMutableString alloc] init];
		[trackItem appendFormat:@"• "];
		if ([itemarray count] > 0 ) {
			for (int i = 0; i < [itemarray count]; i++) {
				[trackItem appendFormat:[itemarray objectAtIndex:i]];
				if (i == [itemarray count]-1) 
					[trackItem appendFormat:@""];
				else
					[trackItem appendFormat:@"\n• "];
			}
		}else {
			trackItem = @"";
		}
		[self setItemText:trackItem];
		[trackItem release];
		if (itemCount > 0)
			[[self sectionArray] addObject:@"item"];
		
		
		// trip
		NSMutableArray *triparray = [[self trackDict] objectForKey:kTripKey];
		[self setCurrentTrackTripArray:triparray];
		[triparray release];
		[[self sectionArray] addObject:@"map"];
	}
}
svveet is offline   Reply With Quote
Old 07-26-2009, 11:42 PM   #25 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,129
Default

Code:
// declare array
[self setFieldDataArray:[[NSMutableArray alloc] init]];
[self setSectionArray:[[NSMutableArray alloc] init]];
These are leaks. Never do alloc/init in the same line as you assign a property. It should be three lines, like this:

Code:
NSMutableArray *fieldArray = [[NSMutableArray alloc] init];
[self setFieldDataArray: fieldArray];
[fieldArray release], fieldArray = nil;
Code:
// name 
NSString *trackName = [[self trackDict] objectForKey:kNameKey];
if (trackName == nil) 
   trackName = @"";
[[self fieldDataArray] addObject:trackName];
[self setNameText:trackName];
[trackName release];
I'm going to say that's the problem. trackName is autoreleased.


By the way, comment "when i click "back button" on the navigationcontroller" would have been a useful piece of information before. That's most likely when the autorelease pool is getting drained. I thought you meant you were literally crashing at the aforementioned line of code.
__________________
BriTer Ideas LLC - Code review, consulting, development. PM for pricing.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:

Last edited by BrianSlick; 07-26-2009 at 11:44 PM.
BrianSlick is offline   Reply With Quote
Reply

Bookmarks

Tags
memory management, memory problem, release

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 248
17 members and 231 guests
ADY, Alsahir, Dani77, Desert Diva, Duncan C, F_Bryant, Grinarn, HemiMG, Herbie, jansan, linkmx, M@realobjects, macquitzon216, prchn4christ, smethorst, spiderguy84
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,882
Threads: 89,228
Posts: 380,761
Top Poster: BrianSlick (7,129)
Welcome to our newest member, jansan
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 01:43 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0