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

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

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

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.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 09-06-2011, 05:04 AM   #1 (permalink)
Registered Member
 
Join Date: Sep 2011
Posts: 33
X-RaY is on a distinguished road
Question Memory management and retainCount

Hi, as I'm a beginner to iPhone development, the memory management of Objective C is quite dazzling for me.

I've written a function which accesses a php page, returning JSON encoded data.
Via the JSON Touch library, I get a dictionary with the result
From there, I'm modifying the data so I can populate a UITableView with it

Before I write everything again (for the second time), here's my code

Code:
-(void)getContactsOnline {
	//Define url to contact the db
	NSURL *url = [NSURL URLWithString:@"<<the url>>"];
	
	//String with returnvalue of the url
	NSString *jsonReturn = [[NSString alloc] initWithContentsOfURL:url];
	
	NSData *jsonData = [jsonReturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
	NSError *error = nil;
	
	//Make a dictionary of the received data
	NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
	
	[jsonReturn release];
	
	//Make an array with all the results in the dictionary with name "Contacts"
	NSMutableArray *keys = [[NSMutableArray alloc] init];
	if(dict)
		keys = [dict objectForKey:@"Contacts"];

	
	NSUInteger keysCount = [keys count]; //Count self.Keys elements
	NSString *theFirstLetter;
	
	//Finding all the first letters of the names of the employees: distinct.
	//Loop through all the rows in keys to find the first characters of all contacts
	NSUInteger index;
	for(int i=0; i<keysCount; i++){
		index = [self.sectionsInTable count];
		
		//Grab the first character of name of contact i in array keys
		theFirstLetter = [[NSString alloc] initWithFormat:@"%C", [[[keys objectAtIndex:i] objectForKey:@"name"] characterAtIndex:0]];
		//If that character isn't in a new array with all the firstLetters, add it.
		if([self.sectionsInTable indexOfObject:theFirstLetter inRange:NSMakeRange(0, index)] == NSNotFound){
			[self.sectionsInTable addObject:theFirstLetter];
		}
		[theFirstLetter release];	
	}
	[self.sectionsInTable sortUsingSelector:@selector(compare:)]; //Order the array alphabetically
	
	
/************************************************************************************\
		Here the array will be populated with Contacts in an 2D array.
		First loop is for the amount of distint first-character-letters. (ex: A,B,D,F,M,P,S) = 7
		Second loop is to add the contact with a certain first-character-letter. (ex: Pablo, Pam, Peter, Paki) 4;
	 ********************************************************************************/
	
	NSMutableArray *inSection = [[NSMutableArray alloc] init];
	NSString *newFirstLetter;
	Contact *employee;// = [[Contact alloc] init];
	NSUInteger sectionsInTableCount = [self.sectionsInTable count];
	NSMutableArray *myArray;
	
	//Loop through all the sections defined in the loop above
	for(NSUInteger i = 0; i<sectionsInTableCount; i++){
		
		//Make space (add array) for section i in array inSection
		myArray = [[NSMutableArray alloc] init]; 
		[inSection addObject:myArray];	//The sections (self.sectionsInTable count)
		[myArray release], myArray = nil;
		
		//Get the first character of the section name of section i
		theFirstLetter = [[NSString alloc] initWithFormat:@"%C", [[self.sectionsInTable objectAtIndex:i] characterAtIndex:0]];
		
		//Loop through the contacts in keys array
		for(NSUInteger x=0; x<keysCount; x++){
			//Grab the first character of the name of contact x
			newFirstLetter = [[NSString alloc] initWithFormat:@"%C", [[[keys objectAtIndex:x] objectForKey:@"name"] characterAtIndex:0]];
			
			//Check if the first character of the section name i is equal to the first character of the name of contact
			if([theFirstLetter isEqualToString:newFirstLetter]){
				//Add employee x with name and department to the array inSection
				employee = [[Contact alloc] initWithName:[NSString stringWithFormat:@"%@", [[keys objectAtIndex:x] objectForKey:@"name"]] andWithDepartment:[NSString stringWithFormat:@"%@", [[keys objectAtIndex:x] objectForKey:@"department"]]];
				[[inSection objectAtIndex:i] addObject:employee];
				[employee release];
			}
			[newFirstLetter release];
		 }
		[theFirstLetter release];
	}
//	[keys release];
		
	id objectInstance;
	id objectInstance2;
	NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] init];
	NSString *letterKey;
	
	NSMutableArray *contactsArray;
	
	//Loop through all the arrays in the array inSection
	for (objectInstance in inSection) {
		//Grab the first character of the first contact in array nr objectInstance-nr for the sectionName
		letterKey = [[NSString alloc] initWithFormat:@"%C", [[[objectInstance objectAtIndex:0] name] characterAtIndex:0]];
				
		//Loop all the contacts of the array objectInstance in array inSection
		contactsArray = [[NSMutableArray alloc] init];		
		for(objectInstance2 in objectInstance){
			//Add all the contacts to a new array
			[contactsArray addObject:objectInstance2];
		}
		
		//Once all contacts are added, add the new array to a new dictionary, with the letterKey as key
		[mutableDictionary setObject:contactsArray forKey:letterKey];
		[contactsArray release];
		[letterKey release];
	}

	//Copy the dictionary into the propery allNames
	self.allNames = [mutableDictionary mutableDeepCopy];
	NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
	[mutableDictionary release];
	NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1

	NSLog(@"keys Count: %d",[keys retainCount]); //2
	NSLog(@"jsonData Count: %d",[jsonData retainCount]); //1
	NSLog(@"error Count: %d",[error retainCount]); //0
	NSLog(@"dict Count: %d",[dict retainCount]); //1
	NSLog(@"theFirstletter Count: %d",[theFirstLetter retainCount]); //2
	NSLog(@"inSection Count: %d",[inSection retainCount]); //1
	NSLog(@"employee Count: %d",[employee retainCount]); //2
	NSLog(@"LetterKey Count: %d",[letterKey retainCount]); //2

	//Correctly released: //Crash on calling retainCount method
/*
	- newFirstLetter
	- jsonReturn
	- contactsArray
 */
}
I removed all (except last) debugging NSLog's for readability.
So, at the end, I wrote all retainCounts of all allocated variables.
With the returned value commented out behind it.
But why aren't the returned values zero, or just crashing my app? (which I think should happen)

Especially this part:
Code:
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
[mutableDictionary release];
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
What's going on there? oO
The analyzer even warns me with: "Reference-counted object is used after it is released"
- even weirder, when i set that last NSLog-mutableDictionary-retainCount below the last NSLog in the function, it seems to behave as expected (crashing the app)

I'm quite consistent with releasing allocated objects (i think)
so another weird part. the keys array.
Allocated as follow:
Code:
NSMutableArray *keys = [[NSMutableArray alloc] init];
if(dict)
	keys = [dict objectForKey:@"Contacts"];
After that, just using the contents, never modifying it again.
Yet, [keys release] isn't allowed.
App either crashes, or says: object is not owned by you.

I know :| a lot of questions with a bunch of code.
After consulting tutorials, books and google, it still dazzles me.

Help highly appreciated!
Grtz,
Me





Pfff, second time I wrote this topic... first time got logged out in the background OMG!
X-RaY is offline   Reply With Quote
Old 09-06-2011, 06:27 AM   #2 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Ypsilanti, Michigan
Age: 63
Posts: 1,549
RLScott is on a distinguished road
Default

After a variable is released for the last time, the retain count is not actually set to zero because the memory is simply put in a pool of available memory that is available for new allocs. It may be allocated to some other purpose immediately or it may just sit there for a while looking exactly the way it did before it was released. Either way, you should not try to access it, even to look at its retain count. Actually there is very little practical use for the retain count property to you as the application programmer. There is too much going on behind the scenes to make that value reliable to you.
RLScott is offline   Reply With Quote
Old 09-06-2011, 06:38 AM   #3 (permalink)
Registered Member
 
Join Date: Jun 2009
Location: Ypsilanti, Michigan
Age: 63
Posts: 1,549
RLScott is on a distinguished road
Default

Quote:
NSMutableArray *keys = [[NSMutableArray alloc] init];
if(dict)
keys = [dict objectForKey:@"Contacts"];
This is wrong because keys is first set to some newly alloced and inited memory, then it is reassigned to an auto-released object, leaving that first block of memory orphaned as a leak.

Releasing keys after that does no good because keys no longer refers to that first alloced block of memory. And it is also wrong because now keys refers to an auto-released object which should not be explicitly released.

Last edited by RLScott; 09-06-2011 at 06:42 AM.
RLScott is offline   Reply With Quote
Old 09-06-2011, 07:56 AM   #4 (permalink)
Registered Member
 
Join Date: Sep 2011
Posts: 33
X-RaY is on a distinguished road
Default

Ah, that makes so much sense!
Thanks a lot

I figure the correct way to do it is:
Code:
NSMutableArray *keys;
if(dict)
keys = [dict objectForKey:@"Contacts"];
For the retainCount,
I come from a background with knowledge in C++.
When 'delete object' is done, even 1 line after the delete statement, there is no way to access that previously deleted object.... well, there is. but didn't encounter it :P

Given the fact that allocated space is still reachable makes sense for these lines of code:
Code:
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
[mutableDictionary release];
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
where the last line isn't valid anymore after 3 lines :P


Yea, i figured retainCount is of little use to developers, but it was my only way to see if I correctly released everything (as testing purpose)

btw: I can safely assume the analyzer sees all leaking objects?
If this question is to Xcode 4 oriented, you can ignore it :P, I don't know if it's available in Xcode 3

Then again, Thank you for your help!
Made things much clearer to me


ow, one final thing, I run analyzer again, and it seems
Code:
NSMutableArray *inSection = [[NSMutableArray alloc] init];
is a Potential leak of an objoect and stored into 'inSection'
Does that honestly have to do with ' = [[NSMutableArray alloc] init]'
or with the numerous:
Code:
myArray = [[NSMutableArray alloc] init]; 
[inSection addObject:myArray];	//The sections (self.sectionsInTable count)
[myArray release], myArray = nil;
and
Code:
employee = [[Contact alloc] initWithName:[NSString stringWithFormat:@"%@", [[keys objectAtIndex:x] objectForKey:@"name"]] andWithDepartment:[NSString stringWithFormat:@"%@", [[keys objectAtIndex:x] objectForKey:@"department"]]];
[[inSection objectAtIndex:i] addObject:employee];
[employee release];
parts in a for loop? (where myArray = nil might be ambiguous)

Last edited by X-RaY; 09-06-2011 at 08:16 AM.
X-RaY is offline   Reply With Quote
Old 09-06-2011, 08:26 AM   #5 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by X-RaY View Post
Hi, as I'm a beginner to iPhone development, the memory management of Objective C is quite dazzling for me.

I've written a function which accesses a php page, returning JSON encoded data.
Via the JSON Touch library, I get a dictionary with the result
From there, I'm modifying the data so I can populate a UITableView with it

Before I write everything again (for the second time), here's my code


I removed all (except last) debugging NSLog's for readability.
So, at the end, I wrote all retainCounts of all allocated variables.
With the returned value commented out behind it.
But why aren't the returned values zero, or just crashing my app? (which I think should happen)

Especially this part:
Code:
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
[mutableDictionary release];
NSLog(@"MutableDic Count: %d",[mutableDictionary retainCount]); //1
What's going on there? oO
The analyzer even warns me with: "Reference-counted object is used after it is released"
- even weirder, when i set that last NSLog-mutableDictionary-retainCount below the last NSLog in the function, it seems to behave as expected (crashing the app)

I'm quite consistent with releasing allocated objects (i think)
so another weird part. the keys array.
Allocated as follow:
Code:
NSMutableArray *keys = [[NSMutableArray alloc] init];
if(dict)
	keys = [dict objectForKey:@"Contacts"];
After that, just using the contents, never modifying it again.
Yet, [keys release] isn't allowed.
App either crashes, or says: object is not owned by you.

I know :| a lot of questions with a bunch of code.
After consulting tutorials, books and google, it still dazzles me.

Help highly appreciated!
Grtz,
Me





Pfff, second time I wrote this topic... first time got logged out in the background OMG!
I haven't read your code - I've got my hands full this morning.

In general, though:

Looking at the retainCount for your objects is not very useful, for a number of reasons.

First and foremost, there's autorelease. If you send an autorelease message to an object, that object gets added to an "autorelease pool". An autorelease pool is a list of objects that will be sent a release message the next time your code returns and the app visits the event loop. The act of sending releases to all the objects in the autorelease pool is known as "draining" the autorelease pool. You can send an autorelease message to an object more than once. If you do, it gets sent multiple release messages when the release pool is drained.

Many system methods return autoreleased objects. It's an excellent way to return objects, because the caller can just use the object and forget about it, and it gets cleaned up later. stringWithFormat is an example of this:

Code:
int points = 10;
NSString* aString = [NSString stringWithFormat: @"You have %d points", points];

NSLog(@"aString retainCount = %d", [aString retainCount])
//Displays 1 because stringWithFormat returns an autoreleased object.
//aString will go away unless you retain it.

[aString retain];

NSLog(@"aString retainCount = %d", [aString retainCount])
//Displays 2 after another retain

[aString autorelease];
NSLog(@"aString retainCount = %d", [aString retainCount])
//Still displays 2, but object will be released soon.

The system will also sometimes retain pointers to your objects if it needs them again. Sometimes temporarily, and sometimes long-term.

There are other games the system frameworks play with your objects that cause the retainCount to be different than what you expect. (For example, sending a copy message to an immutable object might return a new copy of an object, but it is just as likely to simply increment the retain count and return the same object. Because the object is immutable (can't be changed) you don't need to care which it does, but because you don't know which, you don't know what the retain count of the original object will be.

The result of all this is that you really can't use retainCount to tell what's going on with your objects.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Reply

Bookmarks

Tags
count, management, memory, release, retain

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: 374
7 members and 367 guests
apatsufas, JackReidy, jeroenkeij, Sami Gh, tim0504, yomo710
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,671
Threads: 94,121
Posts: 402,903
Top Poster: BrianSlick (7,990)
Welcome to our newest member, JackReidy
Powered by vBadvanced CMPS v3.1.0

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