I have a base Store
class with many methods that all stores inherit. Each store is a singleton. Right now, each store defines its own near-identical method:
+ (Store *)instance {
static SubStore *store = nil;
if (!store) {
store = (SubStore *) [[super allocWithZone:nil] init];
[store setupDefaults];
}
return store;
}
Is there any way to craft a singleton method in a way that the method can simply be added to the base class and inherited by the subclasses?
Stick with simple/stupid, but use dispatch_once.
As soon as you try to make it generic, it gets complex. And buggy.
The sharedInstance method with explicit class naming is dead obvious and it is unlikely you'll repeat it more than a few times in your project.
If, however, you have many subclasses of the one class, then move to an identifier model. I.e. a cache on the abstract store class that can look up store instances by identifier.
I avoid using either +initialize
or, worse, +load
for such initialization. Both are non-deterministic in that their order of execution in relation to other subsystems in your app could be quite variable with seemingly innocuous changes.
Far better to have entirely deterministic initialization. Add a callout in your applicationDidFinishLaunching:
(or one of the others) that explicitly initializes this particular subsystem in your app. It is easy to follow, explicit in both declaration and use, and won't change behavior in odd ways as your codebase evolves.
Rather than using one store static SubStore * store = nil;
, you could use a NSMutableDictionary
which uses class names as keys.
Briefly:
#import <Foundation/Foundation.h>
@interface MONStore : NSObject
- (NSString *)nameOfMostPopularItem;
@end
@implementation MONStore
+ (instancetype)sharedStore
{
// lazy population - not thread safe
static NSMutableDictionary * stores = nil;
if (nil == stores) {
stores = [NSMutableDictionary new];
}
NSString * key = NSStringFromClass([self class]);
if (nil == [stores objectForKey:key]) {
[stores setObject:[self new] forKey:key];
}
return [stores objectForKey:key];
}
- (NSString *)nameOfMostPopularItem
{
return nil;
}
@end
@interface MONMusicStore : MONStore
@end
@implementation MONMusicStore
- (NSString *)nameOfMostPopularItem { return @"Guitar Strings"; }
@end
@interface MONPetStore : MONStore
@end
@implementation MONPetStore
- (NSString *)nameOfMostPopularItem { return @"Puppies"; }
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSLog(@"--- Shopping List ---\nMusic Store:\n\t%@\n\nPet Store:\n\t%@\n",
[MONMusicStore sharedStore].nameOfMostPopularItem,
[MONPetStore sharedStore].nameOfMostPopularItem
);
}
return 0;
}
...not that I would ever do this in my program.
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