Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

sujithkrishnan

macrumors 6502
Original poster
May 9, 2008
265
0
Bangalore
Hi all,

I my iPhone app, i am i am having a static object "staticCatalogObj" implemented as follows....
Code:
+(Catalog *)getCatalogObject
{
	if(staticCatalogObj == nil)
	{
		staticCatalogObj = [[Catalog alloc]init];
		staticCatalogObj.catalogDictionary = [[NSMutableDictionary alloc] init];
		staticCatalogObj.itemsArray = [[NSMutableArray alloc]init];
	
	}
	return staticCatalogObj;
}

I am calling this method in many view controllers to get the same object.
What all things i want to implement / and the necessary releasing statements i want to add to this part??

In many view controllers i have, i am getting this object by

Code:
Catalog localInstanceOfCatalog = [Catalog getCatalogInstance];
// modify the catalog localObject as per requirement...
[localInstanceOfCatalog release];

Is this enough from memory point of view???
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
If you expect client code to release your object after they're done with it, shouldn't you add an extra retain each time you hand it out..?
 

Sbrocket

macrumors 65816
Jun 3, 2007
1,250
0
/dev/null
The first part is the correct way to implement a singleton. You may also want to add the following to make sure that the more than one instance of the class cannot be created (if its only your own code, this doesn't matter as much, but its good practice for libraries and such).

Code:
+(id)alloc {
	NSAssert(sharedCatalogObj==nil,@"Attempted to allocate a second instance of a singleton.");
	return [super alloc];
}

In the second part, you're releasing an object that was never in your ownership. In other words, you're releasing it without retaining it first. You should remove that last release line as long as all that code is occurring within the same method.

If this catalog object is the same as the gigantic object your were talking about in the other thread, then you should consider other ways of accessing the data that won't result in you getting memory warnings all the time because of a single big object taking up all the available memory space.

---

If you expect client code to release your object after they're done with it, shouldn't you add an extra retain each time you hand it out..?

Wrong solution to the problem. The "client code" (which I'm guessing is a reference to the 2nd block there) is incorrect in that it releases an object it never took ownership of. Taking ownership of an object that's not going to be released by the same code, as you suggest he do in the sharedObject method, just compounds the problem. You may get technically correct behavior, but that's bad coding practice to retain in one part of the code simply because a release is expected in a completely separate part. That would be completely unmaintainable.
 

sujithkrishnan

macrumors 6502
Original poster
May 9, 2008
265
0
Bangalore
The first part is the correct way to implement a singleton. You may also want to add the following to make sure that the more than one instance of the class cannot be created (if its only your own code, this doesn't matter as much, but its good practice for libraries and such).

Code:
+(id)alloc {
	NSAssert(sharedCatalogObj==nil,@"Attempted to allocate a second instance of a singleton.");
	return [super alloc];
}

In the second part, you're releasing an object that was never in your ownership. In other words, you're releasing it without retaining it first. You should remove that last release line as long as all that code is occurring within the same method.

If this catalog object is the same as the gigantic object your were talking about in the other thread, then you should consider other ways of accessing the data that won't result in you getting memory warnings all the time because of a single big object taking up all the available memory space.

---



Wrong solution to the problem. The "client code" (which I'm guessing is a reference to the 2nd block there) is incorrect in that it releases an object it never took ownership of. Taking ownership of an object that's not going to be released by the same code, as you suggest he do in the sharedObject method, just compounds the problem. You may get technically correct behavior, but that's bad coding practice to retain in one part of the code simply because a release is expected in a completely separate part. That would be completely unmaintainable.

Uff...
i am wondering why apple put memory management burden over the developer for iPhone rather having garbage collector for it....

My doubt is that i am having many localCatalogInstances in mnay of my classes, like

Code:
localCatalogForFistScreen = [Catalog getCatalogInstance];
localCatalogForSecondScreen = [Catalog getCatalogInstance];

Is all these add to increase in retainCount of the singleton object?
I thought in that way and thats why i  made that release statement there in client who calls the method...
 

sujithkrishnan

macrumors 6502
Original poster
May 9, 2008
265
0
Bangalore
The first part is the correct way to implement a singleton. You may also want to add the following to make sure that the more than one instance of the class cannot be created (if its only your own code, this doesn't matter as much, but its good practice for libraries and such).

Code:
+(id)alloc {
	NSAssert(sharedCatalogObj==nil,@"Attempted to allocate a second instance of a singleton.");
	return [super alloc];
}

In the second part, you're releasing an object that was never in your ownership. In other words, you're releasing it without retaining it first. You should remove that last release line as long as all that code is occurring within the same method.

If this catalog object is the same as the gigantic object your were talking about in the other thread, then you should consider other ways of accessing the data that won't result in you getting memory warnings all the time because of a single big object taking up all the available memory space.

---



Wrong solution to the problem. The "client code" (which I'm guessing is a reference to the 2nd block there) is incorrect in that it releases an object it never took ownership of. Taking ownership of an object that's not going to be released by the same code, as you suggest he do in the sharedObject method, just compounds the problem. You may get technically correct behavior, but that's bad coding practice to retain in one part of the code simply because a release is expected in a completely separate part. That would be completely unmaintainable.

Yeah SB...

This is the object that i mentioned which want to keep it in memory for generating my all views.... All the relation between menus->categories->sub categories are represented in this object...

Eventhough i go for archiving (which i did) i want to load (unarchive) the catalogObject to generate my menus (tableViewControllers)...
 

admanimal

macrumors 68040
Apr 22, 2005
3,531
2
Uff...
i am wondering why apple put memory management burden over the developer for iPhone rather having garbage collector for it....

Garbage collection requires more computation, which equals lower battery life. It can also result in less efficient memory usage (assuming the developer does proper memory management), which is bad for a device with limited memory.
 

Sbrocket

macrumors 65816
Jun 3, 2007
1,250
0
/dev/null
My doubt is that i am having many localCatalogInstances in mnay of my classes, like

Code:
localCatalogForFirstScreen = [Catalog getCatalogInstance];
localCatalogForSecondScreen = [Catalog getCatalogInstance];

Is all these add to increase in retainCount of the singleton object?
I thought in that way and thats why i made that release statement there in client who calls the method...

That local variable assignment alone isn't increasing the retain count of the singleton object, no.
 

whooleytoo

macrumors 604
Aug 2, 2002
6,607
716
Cork, Ireland.
As suggested elsewhere, perhaps the best place to allocate the Catalog object is in the alloc or init methods.

If you do it as you've done above, I'd suggest autoreleasing the Catalog object as you return it; or consistency reasons. The calling code than then retain it, as needed.
 

Sbrocket

macrumors 65816
Jun 3, 2007
1,250
0
/dev/null
As suggested elsewhere, perhaps the best place to allocate the Catalog object is in the alloc or init methods.

If you do it as you've done above, I'd suggest autoreleasing the Catalog object as you return it; or consistency reasons. The calling code than then retain it, as needed.

Err, autoreleasing the singleton object in the sharedObject method? That wouldn't make any sense. The object is created with a retain count of 1 because of the alloc-init on the first call of sharedObject, and in the dealloc method the sharedObject should be released. That means that the singleton class has fulfilled its memory management obligation - it takes ownership of the object at creation, and releases ownership of the object on dealloc.

Here's my idea for solving your overarching problem:

You want to release the singleton object at some point to in the execution to save memory, so create a method like this that you can call in your didReceiveMemoryWarning: methods.

Code:
+(void)destroySingleton {
	if (sharedObj) {
		[self saveSingletonDataToDisk]; // Some method to save all that data to disk
		[sharedObj release];
		sharedObj = nil;
	}
}

Of course, you'd want to add something to your init to load the saved data again from disk. This would mean that the singleton data could be released when not needed (say, on a memory warning sent to a view controller) and created again when needed.

The correct way to use the singleton object in the rest of the code, then, would not be to retain a reference to it in your other classes but to access [MyObjectClass sharedObject] whenever you wanted to use it for some reason. That way if the singleton object was currently residing in memory, it would simply return the pointer to it, and if it didn't exist yet or had been released because of a memory warning it would be loaded from disk again, created, and returned.

The key part here, of course, is to not retain references to the singleton in other parts of your code so that when you call [MyObjectClass destroySingleton] it is, in fact, released and not leaked. That would be bad, and would pretty much result in worse memory performance than before. Of course, you should try to minimize how often you access the shared object since caching and loading it all the time is also bad. I'm not sure exactly what you're storing in there, but try to use it as little as possible or you're not going to realize any benefits with this.

If you need to access it constantly, then you'll probably want to ignore everything I said and find some other solution. To be honest, though, I can't see why you need to keep so much data in memory constantly such that you're getting memory warnings all the time. What exactly are you storing in there that's taking up so much memory, anyway?

This would seem, to me at least, to be the best way to handle your memory problem sujithkrisnan.
 

sujithkrishnan

macrumors 6502
Original poster
May 9, 2008
265
0
Bangalore
Err, autoreleasing the singleton object in the sharedObject method? That wouldn't make any sense. The object is created with a retain count of 1 because of the alloc-init on the first call of sharedObject, and in the dealloc method the sharedObject should be released. That means that the singleton class has fulfilled its memory management obligation - it takes ownership of the object at creation, and releases ownership of the object on dealloc.

Here's my idea for solving your overarching problem:

You want to release the singleton object at some point to in the execution to save memory, so create a method like this that you can call in your didReceiveMemoryWarning: methods.

Code:
+(void)destroySingleton {
	if (sharedObj) {
		[self saveSingletonDataToDisk]; // Some method to save all that data to disk
		[sharedObj release];
		sharedObj = nil;
	}
}

Of course, you'd want to add something to your init to load the saved data again from disk. This would mean that the singleton data could be released when not needed (say, on a memory warning sent to a view controller) and created again when needed.

The correct way to use the singleton object in the rest of the code, then, would not be to retain a reference to it in your other classes but to access [MyObjectClass sharedObject] whenever you wanted to use it for some reason. That way if the singleton object was currently residing in memory, it would simply return the pointer to it, and if it didn't exist yet or had been released because of a memory warning it would be loaded from disk again, created, and returned.

The key part here, of course, is to not retain references to the singleton in other parts of your code so that when you call [MyObjectClass destroySingleton] it is, in fact, released and not leaked. That would be bad, and would pretty much result in worse memory performance than before. Of course, you should try to minimize how often you access the shared object since caching and loading it all the time is also bad. I'm not sure exactly what you're storing in there, but try to use it as little as possible or you're not going to realize any benefits with this.

If you need to access it constantly, then you'll probably want to ignore everything I said and find some other solution. To be honest, though, I can't see why you need to keep so much data in memory constantly such that you're getting memory warnings all the time. What exactly are you storing in there that's taking up so much memory, anyway?

This would seem, to me at least, to be the best way to handle your memory problem sujithkrisnan.


Thanks alot for the detailed explntn...

I am creating a shopping application, which comprising 20 shops, having around 900 items as product...
All these are gettign n=by parsing an xml at a URL...
I want to keep this all shop -product structure to generate the navigation menu for user to navigate..

I am trying to minimize the server-hitting, so i am downlaoding all the shop-products to device...

Okie, i will try some other design....
Thanks again..
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.