iOS singleton with static data - objective-c

I'm working with game center and wanted to have a singleton class for accessing the GK functionality which I've setup, but I then introduced a couple of methods which needed a delegate. Obviously delegates can't really work properly with a singleton, but I want/need the data loaded in this class to be loaded once and be there all the time.
Is there a nice way that I'm missing of keeping the data there all the time, but having the class instantiated as and when it's needed?

Yoy say "singleton class", and by that I assume you mean that this class only has class methods. That's fine, you can still use it, since class objects are still objects. That said, you will probably need to maintain state. Each delegate call will include some parameter that allows the object to identify the sender.
What I would probably do myself is create a NSMutableDictionary in an "initialize" method, then have objects register themselves before sending delegate methods, and when they register create another mutableDictionary, and save that in the first one with the sending object as the key (or some other unique identifier).
Every delegate call has to include the sender, and with that you can retrieve the dictionary associated with that object.

Related

Objective-C: Use singleton vs. use class as an object?

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.

How to share a Data object among a set of delegates?

Following the MVC pattern stressed in various Objective-C programming guides, when I use Model with Controller, I should set the Controller as the delegate of the given Model. Now I have a huge Data object that's very expensive to create, and there're a few Controllers that need to work with this Data object. As long as the delegate property is set to the right Controller the Data object will work fine for THAT controller. Is there a way to share this model among these controllers?
I've brainstormed for a while, but haven't thought of any especially good solutions. A few things that I've come up
use notification center (but it seems expensive to set up such a relationship just for this specific case)
make each method of the Data object take a delegate argument: this is what I'm currently using now, but it is clunky and is reaching its limit
Edit
Thanks for people who have suggested to me using an NSArray. I think I forget to include this subtlty:
For my case say one of the delegates, A, wants to query the Data object by using one of its specific methods. The result would be correct if the delegate field of the Data object is set to A. But from what I understand using an array and calling the method on every delegate wouldn't give me the answer I want.
In fact since my Data object couldn't know which delegate is calling it, it can't give back the correct result even if it knows about all the delegates it should be associated with
Any thought on this?
You could make an NSArray with delegates and then just call the method on every delegate in your array. (Watch out for retain cycles).
If you don't want to use notifications you can try using a multicast delegate approach. In this you would keep an NSMutableArray of delegates instead of a single one. So instead of setting the delegate you would add and remove delegates from your delegate array. When calling a delegate you would then call that delegate method on each delegate in the array, checking each one if it response to that particular callback.
You can also control the order the delegates are called in if you so wish since you create and manage the delegate array yourself.
What I ended up doing is setting up another level of indirection - each Controller will be communicating with a 'middleware' object, which in turn communicates with the Data object. In this way, the common delegate-delegatee approach is preserved while the Data object only needs to be created once - at the expense of added 'middleman' object for each Controller.
In my example, the 'middleware' object will have a Controller set as its delegate property, and when that Controller wants to know information about the Data object, the 'middleware' object will then use its delegate property to query information from the Data object.

Objective C: Giving all objects of a class a pointer to a singleton of another class

I have a custom ViewController class and many instances of it, and I want them all to be able to message the same Model (another custom class, only one instance). Passing pointers to the Model along to new instances of the ViewController seems impractical, especially since the model is lazily instantiated. What is the cleanest, most idiomatic, ARC way to do this?
Usually a singleton in ObjC will have a class method that serves as an accessor for the single instance. The convention is for this to be called either defaultX or sharedX. If your model class is indeed a singleton, you should already have such a method. Since class names are globally available, all you have to do to access the instance anywhere in your program is [MyModelClass sharedModel].

Copying an instance of a singleton to store in array

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.

Is it bad practice for a delegate to have a reference to the object for which it is the delegate?

I'm using the delegate pattern for one of my objects. My idea is that I will be able to swap the delegate out later for a different delegate implementing a different strategy. I suppose this is just as much the strategy pattern as the delegate pattern.
My question is, is it bad practice for my delegate to have a reference back to the object for which it is the delegate? There are a couple properties of that object that I need to have access to regardless of which delegate/strategy I use. If this is bad form, how should I get access to the properties?
Not necessarily. For example, it's quite common for a "controller"-type object to create data objects and views and make itself the delegate of some of those objects in order to properly control things.
It is not at all bad practice. The delegate pattern allows for a class to have a generic way to talk to any number of objects as long as the implement the same protocol. But the class on which you set the delegate also will usually have a number of public properties or methods that allow you to query or alter what the class is doing, in response to which the class may in turn trigger a number of the delegate calls. So you need a reference of the class to which you are the delegate, in order to tell the object to do something different than it is already, and of course to release it when you are through with it!
This is also why it's important to always have any delegate properties as assign, and not retain, properties. That way when the originating class is released it will actually be released, instead of having delegate objects it is holding onto causing a retain loop that keeps both around.
It's also why whenever you are being released, you should set the delegate reference to nil in anything you may have a delegate reference set. This way a class will not have an invalid delegate reference if the delegate is released before the class that uses a delegate.
Generally a dependency should not have a reference back to the dependent object, as this would be a classical circle reference. To avoid having a back-reference you can supply the needed properties as arguments in a delegate method, or you move the properties themselves into the delegate.
I'd say yes, it's bad practice. The idea behind a delegate is that it's effectively a standalone object that receives messages about the object for which it is the delegate (the "delegator"). The delegator should have a reference to the delegate, not the other way around, otherwise it's not a true delegation relationship anymore.
A preferred way to accomplish what you're asking is to provide the sending object along with whatever message your delegate receives. For example, on your delegate, instead of having a delegator property and then receiving, for example, a didDoSomething:(id)anObject method, you could remove the delegator property and send the message delegator:(id)anObject didDoSomething:(id)anotherObject. This way, you keep the delegate distinct from the delegator, but still get access to the delegator's properties when you need them.
This way also has the advantage of not providing access to the delegator in methods when you don't truly need it; for example, your delegate could have a didDoSomething method that takes no arguments, not even a delegator, and is just used for logging, as well as a delegator:(id)anObject didSomethingElse:(id)anotherObject method that calls some properties on the delegator and is much more involved.
Finally, this method allows you to use the same delegate for multiple delegators, since you don't need to update a delegator property for each delegate object.
For a good example of how this works, take a look at the NSURLConnection documentation, specifically its delegate methods - a lot of them take the form connection:didDoSomething:, where the first argument is the connection calling the delegator. Developers commonly define a single connection delegate for multiple connections, implementing their delegate methods to do different things depending on properties of the NSURLConnection object passed in.