With iOS, we always have to be concerned about memory consumption.
I have a class that may have hundreds of instances, and I haven't been able to locate a discussion that indicates whether declaring a static dictionary inside an instance method means that all instances of that class will share the same copy of that dictionary, or each instance will have its own copy, which of course would demolish memory.
BTW, would the answer be any different if this were a class method instead of an instance method?
-(BOOL)doohickeyThing
{
static NSDictionary *someDictionary = [NSDictionary dictionaryWithObjectsAndKeys...
// more code here
}
Thanks.
By definition, there is only one copy of a static variable. No matter how many instances of your class you have, there will only be one copy of the someDictionary. It will get initialized once and every time the method is used, regardless of class instance, the same exact dictionary instance will be used. In other words, it is shared.
This is true whether it is an instance method or a class method.
Related
I've been wondering in what cases it is really necessary to adopt the singleton pattern in objective-C (e.g., define a dedicated class and create a single instance), that using the class as an object won't do.
Particularly, I'm thinking of the following solution:
Define and use appropriate class methods, instead of instance methods on the singleton instance;
Use static variables (file-scope globals), instead of instance variables of the singleton instance;
Use the class object when registering as an observer for notifications, instead of the singleton instance. Although the class object is an objective-C object in its own right (right?), this would require that the notification handler registered be a class method; (is this possible?)
For example, instead of having a Texture class (model object) and a TextureManager singleton (resource manager), you could have all texture creation/cleanup implemented as class methods and static variables of the same Texture class (factory pattern plus some resource management).
Any thoughts on this design?
EDIT:
Now that I think of it, and still in the Texture example above, even if I keep the two classes separate (Texture and TextureManager) I must choose between A. Having the manager be a singleton, and operate it with instance methods, or B. Having the manager be an instanceless, auxiliary class. To clarify:
Texture* myTexture = [[TextureManager defaultManager] textureWithName:#"TextureName"];
// (singleton, client uses instance methods)
versus
Texture* myTexture = [TextureManager textureWithName:#"TextureName"];
// (Class standing in for singleton, client uses class methods)
The latter looks more straightforward and less cumbersome/verbose, but I wonder which design is "more correct". Of course, the former allows for more than one TextureManager instance shall the need arise (not in my case).
I have been thinking about the same thing and I think I have an answer for you.
It depends on what you need to do with it. Neither is necessarily more "correct".
Read on if you want the details of how I came to my conclusion or scroll down to the tl;dr section.
As you said, it would appear (externally) less cumbersome to access the singleton to have the class manage the singleton for you. Essentially you would do this by replacing the singleton's factory method with an initializer method. Looking at Apple's documentation on this you can see where they show a "shared" method that acts as the factory to produce the singleton upon demand.
static MyGizmoClass *sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}
Instead of doing this you could replace the method with a void initializer like so:
+ (void)initializeMyGizmo
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
// whatever else needs to be done to the singleton to initialize it
}
and then ONLY ever use class methods and allow the MyGizmoClass to manage updates to the singleton like [MyGizmoClass setGizmoName:#"Gadget"].
NOTE: In this scenario it would be confusing to someone looking at the .h file to see properties, in which case they may come to the conclusion that they should create an instance of the object themselves, or be able to have access to the singleton in some form or fashion. So if you were to go the route of encapsulating access to the singleton it would not be wise to use public variables.
To that point:
If you do limit access to solely through the class itself you lose any getters and setters or other free things that come along with properties. This means that if MyGizmoClass were to have as part of it's model an NSString *gizmoName you would be forced to create custom getters and setters for this "property" and keep it either as an ivar or property in an interface extension in the .m file (i.e. private) of the singleton class, or as an adjacent static variable.
So this begs the question (and is what got me pondering in the first place), should we even include the line static MyGizmoClass *sharedGizmoManager = nil; at all or can we nix the internal interface extension altogether and replace any possible ivars or properties that we want to limit access to with static implementations in the implementation?
I answered that already...
It depends on what you need to do with it.
tl;dr
First Scenario
If you ever (even the slightest chance) need to subclass your
TextureManager or could create multiple instances of it (making it
no longer a singleton) it would be better to stick to the regular
Apple convention for a singleton.
This includes multiple "singletons" wherein you might have several
TextureManagers preconfigured with different settings.
In this case you would use properties as you need them (publicly or
privately) as well as ivars. You could also use a mix of ivars and
statics but you would still always need to have a static instance of
your TextureManager inside of the TextureManager implementation.
Second Scenario
If you ONLY will ever need ONE instance of the TextureManager and it will run completely standalone with no intermixing further down the line then you could completely remove the static instance of your class within the implementation in the .m file and replace ivars and properties with static variables within that implementation.
This can be useful if you are storing off properties or settings in CoreData and only need them for configuration.
Just remember in this case you will have to create all getters and setters for the static variables and will only be able to access them using class methods (but that's sorta the point).
Other Interesting Stuff
This answer offers an interesting solution to the question of when and how to call the "initializer" method or create the singleton. This can be used with each scenario to either initialize the singleton in the first scenario, or preload defaults into the class-level statics in the second scenario.
If you want to stick with a static singleton in the implementation you might look at this article to give you a better idea at the true "global scope" of your singleton.
Yes you can definitely make a Texture class without needing a singleton.
Singletons probably should not be created and used as an object.
Singletons can be used for many important things.
I certainly don't know all of the things they can be used for, but i will tell you what i have used them for in the past.
I usually use singletons for level navigation in a game with many levels (like Angry Birds).
By level navigation, i mean... when a player completes a certain level in a game i simply call a class method on the singleton and pass in the level number, then the singleton's class method figures out which level is next (if user presses 'next level' button).
I can help you understand the Singleton class better and when it applies.
Pattern : Singleton
Intent : Enforce that a class can only have a single instance, as well as making that instance accessible to any other object.
Motivation : Sometimes we need to make sure that there exists only a single object of a certain type in our problem domain. Example: A student carries around only a single backpack, which he can fill with books. We would not want to relate him to secondary backpack, with even more books.
Use when :
There is need for only a single instance of a class, and that instance must be accessible from different objects within your code.
When you (possibly) need to be able to add more functionality to that class by subclassing it.
I would like to take a singleton class that gets used by multiple view controllers, copy it, and save it to an array that will be displayed in another view controller with a table view that will show multiple instances of that class. This array will eventually be archived to be retrieve with the same data.
Before I attempt this, is there a way I can duplicate this singleton instance, save it to the array, re-initialize it for the next use, and so on (without getting the same exact previously uninitialized object)?
It's not a singleton that you want.
A singleton must always return the same instance.
What you want is a normal class that maybe have a convenience class method to feed you some pre-populated object.
If it's possible to create more than one instance of an object it's not a singleton anymore.
But your singleton class could hold a variable amount of instance of other class that you wish to display.
So in that way what you are asking could be possible, but without the copy part on the singleton.
I'm not sure where you are going with this and if it's the best way to
go but here is an idea :
you can have a singleton class that would hold an array of an other class. So you could call your singleton like this
TheSingletonClassName *mySingleton = [TheSingletonClassName sharedTheSingletonClassName];
OtherClass *myOtherClass = [mySingleton newOtherClassInstancePlease];
In your newOtherClassInstancePlease method you implement the necessary thing to store that new object into an array, that you can distribute like this
NSArray *otherClassArray = [mySingleton allOtherClasses];
Or NSMutableArray if you prefer.
With that you would be able to share, create new and even delete object. if you implement the necessary method on your singleton.
But again don't copy a singleton, if the singleton is well implemented sending it a copy call should throw an exception, or return the single singleton instance that exists.
I am learning Objective-C and I don't really understand the difference between an instance and an object. They commonly use both terms. Also, why is the alloc method applied to the class and the init method applied to the object?
An instance is the same as an object, hence why both terms are used and can be used interchangeably — an instance of NSString, or an NSString object.
+alloc is a class method responsible for allocating the memory needed to store a new instance/object, and zeroing-out that memory. It returns a newly created instance/object.
-init, on the other hand, is responsible for further initialising this new instance;1 for example, assigning default values to instance variables. Since -init operates on an existing instance, it’s an instance method.
1In some cases -init might return an instance different from the one created by +alloc.
Is it possible to share one parameter of a class among all the instances of this class, in objective-c?:
#interface Class1 : NSObject {
NSString* shared; /** shared among instance (this is not, but defined somehow) **/
NSString* non_shared; /** other parameters non shared **/
}
In the program then, each instance of Class1 has its own non_shared variables (as usual), but all access the same shared one (when one instance changes it all can see it).
One possibility is to hide the variable as a property and use a singleton in the setter/getter functions, but I don't know if there is a simple way.
Thanks,
Edu
Class variables (called static in many other OOP languages) are actually a bit of a pain in Objective-C. You have to declare a static global variable in the class' module (.m) file and reference that variable. You should add class-level getter/setters to encapsulate access to the static global variable. Your getter can alloc/init an object and put it in the variable if it is uninitialized before returning it.
If the static variable holds an instance (e.g. an NSString instance in your example), you need to make sure it doesn't get alloc/initialized more than once. Take a look at dispatch_once if you're on OS X 10.6 or greater to guarantee single initialization.
I know that class variables are declared in memory (as opposed to on the stack) when the class is initialized, and I know how class methods are basically used. But I have some questions about class methods that aren't answered in the basic documentation.
Are class method also declared in memory? What about any object declared within these class methods? Are they 'static' in scope? What about any objects that are passed into a class method as parameter? Are those also 'static'?
Does repeatedly calling a class method mean all the objects declared within it are allocated again and again (one per method call), or are they living in one location in memory? Do they get cleared at every run?
For example, what happens to the do_something method here:
+ (void) main
{
while (i < MAX)
{
[MyClass do_something];
}
}
+ (void) do_something
{
NSMutableArray *array = [[NSMutableArray alloc] init];
...
[array release];
}
Class methods follow the same rules as object (instance) methods except you cannot access instance variables from class methods, obviously because ivars get allocated per object instance.
In your example "array" is allocated on heap with each call, as usual.
All variables are stored "in memory", no matter their storage type (static, automatic, free store), location (stack or heap), linkage or scope. A variable is static only if it's declared static. Otherwise, variables in class methods, whether parameters or local variables, have function or local scope, automatic storage, no linkage and are stored on the stack.
Class methods have global scope and external linkage, though you can send a message to an object (including classes) even if there isn't a handler in scope. Internal linkage should be possible, but I don't think the language supports declaring methods with internal linkage. Storage type and location doesn't really apply to methods, but you could say methods have static storage.
When calling the +(void) do_something method the array object will be initialised, as your code specifies, every time. It is only declared the scope of that method.
You can declare static variables in the class scope. These, as you'd expect, are accessible to all instances and class (aka static) methods.
See: http://www.otierney.net/objective-c.html#class