Consider this code:
+(id)sharedInstance
{
static dispatch_once_t pred;
static MyClass *sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[MyClass alloc] init];
});
return sharedInstance;
}
If I follow this singleton design pattern I can make the following assumptions:
The allocation and initialization will only be executed once thanks
to GCD.
The sharedInstance class variable can only be accessed from
within this implementation and shared among the class regardless of the instance.
First time I create the instance I would do something like:
MyClass *something = [MyClass sharedInstance];
my question is, If I call the previews code again but like this:
MyClass *somethingOther = [MyClass sharedInstance];
I can only think of one outcome.
Outcome:
static MyClass *sharedInstance = nil;
Makes sharedInstance class variable point to nil and a nil is returned so somethingOther will be nil.
But I thought that what was supposed to happen in a singleton is that the shared instance would be returned instead.
Now consider this code:
+ (MotionManagerSingleton*)sharedInstance {
static MotionManagerSingleton *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
Here the
static MotionManagerSingleton *_sharedInstance;
Doesnt set my variable to nil, but i thought that all object pointers are initialized to nil by default.
My question is, how are these class methods returning the "sharedInstance"?
Thanks
One. Non-initialized pointers are non-initialized.
static MotionManagerSingleton *_sharedInstance;
won't make your MotionManagerSingleton point to nil. It will point to an undefined (garbage) location.
Two. Variables declared static are initialized only once (yes, the syntax is a bit inconsistent with the semantics), so your first implementation won't null out the returned shared instance. That's a perfectly fine implementation.
Related
I'm playing around with idea of singleton cache. The setup is quite simple:
In my singleton class, I am instantiating one instance as follows:
+(SharedInstanceTest*)sharedInstace
{
static SharedInstanceTest *sharedInstace=nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace=[[SharedInstanceTest alloc]init];
});
NSLog(#"Share Instance Allocated");
return sharedInstace;
}
+(id)allocWithZone:(NSZone *)zone
{
return [self sharedInstace];
}
Now in the rootViewController, I am calling the sharedInstance just so that I can see the NSLog to make sure it has been instantiated.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[SharedInstanceTest sharedInstace];
}
I get no NSLog. Any idea why?
Do not override allocWithZone. It is probably causing a loop or something when you do [SharedInstanceTest alloc].
You can override allocWithZone: in order to prevent clients from creating more instances. You just can't use alloc to create the shared instance, because that will end up calling allocWithZone:; then you have an infinite loop, as SB. answered.
You can do something like this (to convert to ARC, just remove the retain in allocWithZone:):
#import "MySingleton.h"
static MySingleton * defaultMySingleton = nil;
//MySingleton * defaultMySingleton = nil;
//void initialize_defaultMySingleton(void) {
// [MySingleton defaultMySingleton];
//}
#implementation MySingleton
+ (MySingleton *)defaultMySingleton {
// Create the instance if it has not been already.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Call super's implementation because allocWithZone: is overridden
// to call defaultMySingleton
// The class owns this instance.
defaultMySingleton = [[super allocWithZone:NULL] init];
});
return defaultMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
// Users of alloc, although they shouldn't be using this,
// will expect a +1 retain count. Bump it to allow for eventual release.
return [[self defaultMySingleton] retain];
}
- (id)init
{
// If defaultMySingleton exists, then it is self here. Just return it.
if( defaultMySingleton ) return defaultMySingleton;
// Otherwise, do normal setup.
self = [super init];
if( !self ) return nil;
return self;
}
#end
This was inspired by Peter Hosey's singleton blog post, though he seems to have changed his implementation quite a bit since I last read it.
Nomaly I used to build a singleton the following recipe:
+ (MyClass *)sharedInstance
{
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
// Init variables
});
return _sharedInstance;
}
Then I can call methods as following:
[[MyClass sharedInstance] anyInstanceMethod];
But, what happen when any init variables are configurables from outside the class?
My approach is create two class methods, one of them with configurables variables:
+ (MyClass *)sharedInstanceWithVariableOne:(NSString*)aParamOne andVariableTwo:(NSString*)aParamTwo
{
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
// Init configurables variables
_sharedInstance.paramOne = aParamOne;
_sharedInstance.paramTwo = aParamTwo;
});
return _sharedInstance;
}
And the second one as proxy to this last one with default values:
+ (MyClass *)sharedInstance
{
return [MyClass sharedInstanceWithVariableOne:#"value1" andVariableTwo:#"value2"];
}
So, if you want to use singleton class with configure variables, you should call first of all sharedInstanceWithVariableOne:andVariableTwo and then only sharedInstance.
I think this approach is not the best and I'm looking forward to use others.
Thanks in advance.
Thanks for your fast responses.
As you says, it's not a singleton.
I'm going to use the same behaviour as [NSURLCache setSharedURLCache:]and [NSURLCache sharedURLCache].
Interface
// MyClass.h
#interface MyClass : NSObject
+ (MyClass *)sharedMyClass;
+ (void)setSharedMyClass:(MyClass *)object;
- (id)initWithParamOne:(NSString)p1 andParamTwo:(NSString)p2;
#end
Implementation
// MyClass.m
#interface MyClass ()
#property(nonatomic, strong) NSString *paramOne;
#property(nonatomic, strong) NSString *paramTwo;
#end;
#implementation MyClass
static MyClass *_sharedInstance = nil;
+ (MyClass *)sharedMyClass
{
if (_sharedInstance == nil) {
_sharedInstance = [[MyClass alloc] initWithParamOne:#"value1" andParamTwo:#"value2"];
}
return _sharedInstance ;
}
+ (void)setSharedMyClass:(MyClass *)object
{
_sharedInstance = object;
}
- (id)initWithParamOne:(NSString)p1 andParamTwo:(NSString)p2
{
self = [super init];
if (self) {
_paramOne = p1;
_paramTwo = p2;
}
return self;
}
Then I could use [[MyClass sharedMyClass] anyMethod]
There are many ways to design what you are after with your shared instance. (It is not a singleton as many comments point out, for that there must be only one instance of the class possible. However that said the shared instance pattern is often used as a "poor man's" singleton with no direct calls to any init methods. Back to the question...) Maybe the following will suit you:
+ (void) setSharedInstanceParameterOne:(NSString*)aParamOne
andParameterTwo:(NSString*)aParamTwo
{
MyClass *_sharedInstance = self.sharedInstance;
_sharedInstance.paramOne = aParamOne;
_sharedInstance.paramTwo = aParamTwo;
}
Now you use [MyClass setSharedInstanceParameterOne:p1 andParameterTwo:p2] to set/change the parameters of the shared instance, and [MyClass sharedInstance] (or MyClass.sharedInstance, though some might have a philosophical discussion about that) to access it.
How do I convert (or create) a singleton class that compiles and behaves correctly when using automatic reference counting (ARC) in Xcode 4.2?
In exactly the same way that you (should) have been doing it already:
+ (instancetype)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
if you want to create other instance as needed.do this:
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
else,you should do this:
+ (id)allocWithZone:(NSZone *)zone
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
This is a version for ARC and non-ARC
How To use:
MySingletonClass.h
#interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
#end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
#implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
#end
This is my pattern under ARC.
Satisfies new pattern using GCD and also satisfies Apple's old instantiation prevention pattern.
#implementation AAA
+ (id)alloc
{
return [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
abort();
}
+ (instancetype)theController
{
static AAA* c1 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
c1 = [[super allocWithZone:nil] init];
// For confirm...
NSLog(#"%#", NSStringFromClass([c1 class])); // Prints AAA
NSLog(#"%#", #([c1 class] == self)); // Prints 1
Class real_superclass_obj = class_getSuperclass(self);
NSLog(#"%#", #(real_superclass_obj == self)); // Prints 0
});
return c1;
}
#end
Read this answer and then go and read the other answer.
You must first know what does a Singleton mean and what are its requirements, if you don't understand it, than you won't understand the solution--at all!
To create a Singleton successfully you must be able to do the following 3:
If there was a race condition, then we must not allow multiple instances of your SharedInstance to be created at the same time!
Remember and keep the value among multiple invocations.
Create it only once. By controlling the entry point.
dispatch_once_t helps you to solve a race condition by only allowing its block to be dispatched once.
Static helps you to “remember” its value across any number of
invocations. How does it remember? It doesn't allow any new instance with that exact name of your sharedInstance to be created again it just works with the one that was created originally.
Not using calling alloc init (i.e. we still have alloc init methods since we are an NSObject subclass, though we should NOT use them) on our sharedInstance class, we achieve this by using +(instancetype)sharedInstance, which is bounded to only be initiated once, regardless of multiple attempts from different threads at the same time and remember its value.
Some of the most common system Singletons that come with Cocoa itself are:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Basically anything that would need to have centralized effect would need to follow some sort of a Singleton design pattern.
Alternatively, Objective-C provides the +(void)initialize method for NSObject and all its sub-classes. It is always called before any methods of the class.
I set a breakpoint in one once in iOS 6 and dispatch_once appeared in the stack frames.
Singleton Class : No one can create more than one object of class in any case or through any way.
+ (instancetype)sharedInstance
{
static ClassName *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ClassName alloc] init];
// Perform other initialisation...
});
return sharedInstance;
}
// You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only.
-(MyClass)init
{
return [ClassName sharedInstance];
}
There are two issues with the accepted answer, which may or may not be relevant for your purpose.
If from the init method, somehow the sharedInstance method is called again (e.g. because other objects are constructed from there which use the singleton) it will cause a stack overflow.
For class hierarchies there is only one singleton (namely: the first class in the hierarchy on which the sharedInstance method was called), instead of one singleton per concrete class in the hierarchy.
The following code takes care of both of these problems:
+ (instancetype)sharedInstance {
static id mutex = nil;
static NSMutableDictionary *instances = nil;
//Initialize the mutex and instances dictionary in a thread safe manner
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mutex = [NSObject new];
instances = [NSMutableDictionary new];
});
id instance = nil;
//Now synchronize on the mutex
//Note: do not synchronize on self, since self may differ depending on which class this method is called on
#synchronized(mutex) {
id <NSCopying> key = (id <NSCopying>)self;
instance = instances[key];
if (instance == nil) {
//Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
id allocatedInstance = [self alloc];
//Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
//Do this right after allocation to avoid the stackoverflow problem
if (allocatedInstance != nil) {
instances[key] = allocatedInstance;
}
instance = [allocatedInstance init];
//Following code may be overly cautious
if (instance != allocatedInstance) {
//Somehow the init method did not return the same instance as the alloc method
if (instance == nil) {
//If init returns nil: immediately remove the instance again
[instances removeObjectForKey:key];
} else {
//Else: put the instance in the dictionary instead of the allocatedInstance
instances[key] = instance;
}
}
}
}
return instance;
}
#import <Foundation/Foundation.h>
#interface SingleTon : NSObject
#property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;
#end
#import "SingleTon.h"
#implementation SingleTon
+(SingleTon *) theSingleTon{
static SingleTon *theSingleTon = nil;
if (!theSingleTon) {
theSingleTon = [[super allocWithZone:nil] init
];
}
return theSingleTon;
}
+(id)allocWithZone:(struct _NSZone *)zone{
return [self theSingleTon];
}
-(id)init{
self = [super init];
if (self) {
// Set Variables
_name = #"Kiran";
}
return self;
}
#end
Hope above code will help it out.
if you need to create singleton in swift,
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
or
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
you can use this way
let sharedClass = LibraryAPI.sharedInstance
I have a following code in my singleton class
static MySingleton *gManager;
+(void)initialize
{
if(self == [MySingleton class])
{
gManager = [[MySingleton alloc] initWithServices:[[MyServices alloc] init]];
}
}
+(MySingleton *)sharedInstance
{
return (gManager);
}
Unfortunately, during the unit tests I see that gManager is an instance of type SenTestCaseRun. I cant seem to figure out why?
So a call like
[[MySingleton sharedInstance] myFunction];
results in an error that myFunction is an unknown selector although it exists in the MySingleton class.
It is of type SenTestCaseRun because I checked using NSStringFromClass function.
Any pointers? Already banged my head for 3-4 hours on this :(.
it may be better to just put the initialization code inside the shared instance method
+(MySingleton *)shared
{
static MySingleton *sharedInstance = nil;
if(sharedInstance == nil){
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
also in your code you are comparing an object to a class which will never be true instead of comparing [self class] to [MySingleton class].
Put a breakpoint in +initialize to make sure this variable is set correctly. If that doesn't explain it, use a watchpoint on it to see who's modifying it.
I'm trying to write a class that I can subclass to have an instant singleton. Here's what I have so far. It works until one of its subclasses calls another via sharedInstance which causes a huge loop that eventually runs out of memory.
Any ideas?
static NSMutableDictionary *sharedInstances = nil;
#implementation Singleton
+ (Singleton*)sharedInstance
{
[Singleton initSharedInstances];
Class myClass = [self class];
Singleton * sharedInstance = [sharedInstances objectForKey:myClass];
#synchronized(myClass)
{
if (sharedInstance == nil)
{
sharedInstance = [[myClass alloc] init];
[sharedInstances setObject:sharedInstance forKey:myClass];
}
}
return sharedInstance;
}
+ (void) initSharedInstances
{
if (sharedInstances == nil)
{
sharedInstances = [[NSMutableDictionary alloc] init];
}
}
#end
Why are you bothering with all this? If you're trying to enforce singleton behavior in the superclass by overriding -retain, -release, -retainCount, and +allocWithZone: then you're doing something completely unnecessary. Far more simple is just to provide a +sharedInstance method and do nothing else. If the user really wants to call +alloc/-init, they can, it just won't do them much good. For examples of this type of singleton in the frameworks, look at NSUserDefaults and NSFileManager (though in the case of the latter, these days Apple actually recommends you ignore the shared instance and alloc/init your own instances of NSFileManager).
In order to do this simple shared instance stuff, all you have to do is, in the singleton class, implement the following:
+ (id)sharedInstance {
static MyClass sharedInstance;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
//sharedInstance = [[MyClass alloc] init];
sharedInstance = [MyClass alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
I'm trying to write a class that I can subclass to have an instant singleton. Here's what I have so far. It works until one of its subclasses calls another via sharedInstance which causes a huge loop that eventually runs out of memory.
This sounds like you are describing mutual-recursion. If subclass1 calls subclass2 and subclass2 calls subclass1 then you need to break the loop somewhere, just as with simple self-recursion.
Your sharedInstance itself should not cause infinite recursion unless the init method you invoke itself invokes sharedInstance...