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:
static
variables (file-scope globals), instead of instance variables of the singleton instance;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).
By using singletons in your project, you start to create technical debt. Singletons tend to spread like a virus because it's so easy to access them. It's difficult to keep track of where they're used and getting rid of a singleton can be a refactoring nightmare in large or complex projects.
What is a Singleton Class? A singleton class returns the same instance no matter how many times an application requests it. Unlike a regular class, A singleton object provides a global point of access to the resources of its class.
Singletons hinder unit testing: A Singleton might cause issues for writing testable code if the object and the methods associated with it are so tightly coupled that it becomes impossible to test without writing a fully-functional class dedicated to the Singleton.
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.
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
TextureManager
s 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.
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).
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With