Reputation: 7845
While recently working with Objective-C and various libraries written in it, I've noticed two really popular singleton patterns. One version fetches the singleton instance and calls its instance methods and other version only exposes class methods and never gives you an instance to work with. All have the purpose of abstracting access to a single resource (StoreKit, CoreData, Parse API etc.). For example, here's the former approach used in MKStoreKit:
// initialize singleton during app boot
[MKStoreManager sharedManager]
// sometime later in the app
[[MKStoreManager sharedManager] buyFeature:kFeatureAId
onComplete:^(NSString* purchasedFeature)
{
NSLog(@"Purchased: %@", purchasedFeature);
}
onCancelled:^
{
NSLog(@"User Cancelled Transaction");
}];
or alternatively NSUserDefaults, UIApplication etc.. The other approach can be seen in MagicalRecord or here with Parse API:
// configure API credentials sometime during app boot
[Parse setApplicationId:@"123456"
clientKey:@"123456"];
// sometime later
PFObject *testObject = [PFObject objectWithClassName:@"TestObject"];
[testObject setObject:@"bar" forKey:@"foo"];
[testObject save];
What are some pros and cons of the two approaches and is one of them fundamentally better than the other?
Not having to retrieve the shared instance saves some screen estate (the performance difference is likely irrelevant), but am I screwing myself in some other way, for example, testability-wise?
Thanks!
Upvotes: 39
Views: 7489
Reputation: 726849
There are two different ways to implement the approach based on class methods:
The implications of the first implementation are that everything you can do with a singleton, you can do with the hidden singleton:
If you go for an implementation that does not use a singleton, you would be relying on static variables to keep your current state. That is a legitimate choice, but the initialization pattern becomes different (perhaps even using a dispatch_once
), you cannot switch the implementation in the middle without relying on some ugly if
conditions, and using a subclass becomes a lot more tricky.
Testing the first implementation is somewhat easier than testing the second one, because you can provide a separate implementation of the singleton for testing, perhaps through the back door; with a static-based implementation, this route cannot be taken.
To summarize, I would use a singleton-based solution, with the singleton optionally hidden behind a "facade" that provides access to singleton's methods. I would not use an implementation where all state must be placed in static variables.
Upvotes: 29
Reputation: 318884
One advantage of the singleton approach is that it becomes trivial to allow other instances if you need to. If you take the class method approach, that's all you get without a lot of refactoring.
Upvotes: 7