How can I make a viewcontroller singleton, to then use this code:
FacebookManager *manager = [FacebookManager sharedManager];
[manager openSessionWithAllowLoginUI:NO]
??
That's not necessarily a singleton. A singleton can only have one instance at any given time. Shared instances are similar, but don't prevent additional instances from being created.
You can implement a shared instance with a static variable and a class method like this:
+ (FacebookManager *)sharedManager
{
static FacebookManager *shaderManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shaderManager = [[FacebookManager alloc] init];
});
return shaderManager;
}
Don't forget to declare the class method in your header.
Related
There are different types of singleton implementation.
First:
static MyGlobalClass *instance = nil;
+(MyGlobalClass*)myinstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [MyGlobalClass new];
}
}
return instance;
}
Second:
+(PKShareClass *)sharedInstance
{
static PKShareClass *shaedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shaedInstance = [[PKShareClass alloc]init];
});
return shaedInstance;}
And finally with
static NSOperationQueue * _connectionQueue = nil;
+ (NSOperationQueue *) connectionQueue{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_connectionQueue)
{
_connectionQueue = [[NSOperationQueue alloc] init];
}
});
return _connectionQueue;
}
Here my question is what it means when we initialize like first and second ??
And third one with NSOperationQueue. What is the use when we initialize like third one?
Hard to find the meaning.
I'm afraid that i can't give you a link which can explain clearly about both 3 way but i will tell you what i understand.
First way: You create instance is a static variable of MyGlobalClass class. In myinstance method, you check if instance is initialized or not. If not, initialize instance. After all, return value of instance. Because instance is a static variable of MyGlobalClass so when you call [MyGlobalClass myinstance], it's always one object.
Second way: You create shaedInstance is a static variable of method sharedInstance. When you call dispatch_once(&onceToken, the code inside block is called only one time. About dispatch_once, you can take a look here. Because the initialization method is called only one time, shaedInstance is always one object when you return it. Actually, there is no different if shaedInstance is a static variable of PKShareClass class. You can use both 2 ways.
Third way: As you can understand after i explain about second way. This way is same like second way when shaedInstance is a static variable of PKShareClass class. But you don't need to check !_connectionQueue inside dispatch_once. Because it runs only one time and grossly it's always nil at the first time. This way can refactor like:
static NSOperationQueue * _connectionQueue = nil;
+ (NSOperationQueue *) connectionQueue{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_connectionQueue)
_connectionQueue = [[NSOperationQueue alloc] init];
});
return _connectionQueue;
}
Hope my answer can help you understand 3 ways easier ;)
This question already has an answer here:
What is the use of Singleton class in objective-c? [duplicate]
(1 answer)
Closed 7 years ago.
I am new to iOS development and I have gone through singleton class. I understood the concept, but having doubts in implementing the singleton class. Can anyone please share source code of the real time example using singleton class.
This is how a GCD for singleton class looks like.
Suppose there is a class that you made, MySingleTonClass which is a subclass of NSObject
MySingleTonClass.h
+(instanceType)sharedManager;
#property (nonatomic, strong) NSString *userName;
MySingleTonClass.m
+(instanceType)sharedManager{
static MySingleTonClass *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[MySingleTonClass alloc]init];
});
return manager;
}
Now you call this singleTon Class in some other class suppose in ViewController.m. First Import the Class
#import MySingleTonClass.h
-(void)viewDidLoad{
MySingleTonClass *manager = [MySingleTonClass sharedManager];
manager.userName = #"ABCDE";
//manager is the singleton Object
}
Edit
Now suppose you want to access this same value. then suppose in some other ViewController, after ViewController
Suppose in SecondViewController.m
#import "MySingleTonClass.h"
-(void)viewDidLoad{
MySingleTonClass *manager = [MySingleTonClass sharedManager];
NSLog (#"%#",manager.userName);
// This would still log ABCDE, coz you assigned it the class before, So even if you create a new object called manager here, it will return the same Manager you created before.
manager.userName = #"Myname"; //Now the value changed to MyName untill you change it again, in the lifetime of this application.
}
I hope i could make you understand the concept of it.
As you know, dispatch_once_t is a GCD snippet that makes the code inside of it invoke only ONCE per application run. Any code you write inside it will be run, or rather invoked only once in the lifetime of the application being active.
Check out this link for the original source - http://getsetgames.com/2009/08/30/the-objective-c-singleton/
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
static User *defaultUser;
+ (User *)defaultUser
{
if (!defaultUser)
{
defaultUser = [self new];
// do something...
}
return defaultUser;
}
There are two ways:-
1) We can create singleton class using **GCD** dispatch_once
in this only one object will create if existing object is there then it will refer to them.
+(id)sharedManager
{
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
2) Second way is follows:-
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
suppose this above method is written in class **MyManager** then u can use that as follow
MyManager *sharedManager = [MyManager sharedManager];
hope this will help u.
I have a subclass called MyObjectManager which inherits from RKObjectManager
in MyObjectManager I initialize RestKit (set base url etc etc)
I then subclass MyObjectManager into two different classes:
UserManager and GameManager. Each implement different functions
at first I call UserManager sharedManager and it works fine. I later called GameManager sharedManager with a relevant function, but I get a "unrecognized selector sent to instance" error as it refers to the latter as a UserManager.
I read in the guidelines that it's accepted to subclass RKObjectManager several times, what am I missing?
MyObjectManager implementation:
static MyObjectManager *sharedManager = nil;
#implementation MyObjectManager
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *baseUrl = [NSString stringWithFormat:#"http://ip/api"];
NSURL *url = [NSURL URLWithString:baseUrl];
sharedManager = [self managerWithBaseURL:url];
sharedManager.requestSerializationMIMEType = RKMIMETypeJSON;
[sharedManager setupRequestDescriptors];
[sharedManager setupResponseDescriptors];
});
return sharedManager;
}
That's because RKObjectManager +sharedManager is a class method. It will instantiate the shared manager on first call and then return it on further calls. Your first call to sharedManager did instantiate a RKObjectManager and your call to GameManager sharedManager did return the same instance. This instance being of class RKObjectManager , it doesn't implement GameManager's functions - thus the unrecognized selector sent to instance error.
That's perfectly acceptable to subclass RKObjectManager but you should probably also subclass the class method +sharedManager inside GameManager to return your own static instance instead of relying on RKObjectManager's one.
EDIT : Based on your edit, you should try to subclass +managerWithBaseURL inside GameManager so that is returns an instance of GameManager instead of RKObjectManager.
I have a singleton that is initialized like all singletons, with something like this:
+ (MySingleton *)sharedInstance
{
static MySingleton *sharedMyInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyInstance = [[MySingleton alloc] init];
});
return sharedMyInstance;
}
In my case I want to add some code to initialize the singleton but because sharedInstance is a class method I cannot call instance methods from there.
So I always have to have this pattern:
MySingleton *sing = [MySingleton sharedInstance];
[sing initialize];
Ok, I can do this
MySingleton *sing = [[MySingleton sharedInstance] initialize];
but this will generate another problem because if initializing the singleton is the only thing I want at this point, sing is not being used and this is ugly code.
I suppose I can do simply
[[MySingleton sharedInstance] initialize];
and Xcode will not complain, but this does not sound good.
Is there another way to do this?
Check your code ;-) Specifically the line:
sharedMyInstance = [[MySingleton alloc] init];
You have to implement init and there is where you'll initialize the instance variables of your singleton (AKA shared instance). It will be called the first time the shared instance is used.
I have implemented a singleton object using the regular pattern. My question is: is it possible to set this object back to nil, so that on a later called to [MySingleton sharedInstance] the object gets re-initialised?
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
// We can still have a regular init method, that will get called the first time the Singleton is used.
- (id)init
{
self = [super init];
if (self) {
// Work your initialising magic here as you normally would
}
return self;
}
My guess is that
MySingleton *shared = [MySingleton sharedInstance];
shared = nil;
only sets the local pointer shared to nil. After all, shared is declared as static.
Your assumption about the local reference is correct, it won't affect your singleton.
To be able to reinitialize the singleton you need to move the static variable out of your method, so it's accessible by the whole class.
static MySingleton *sharedInstance = nil;
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
+ (void)resetSharedInstance {
sharedInstance = nil;
}
Note that you cannot use dispatch_once anymore, since your singleton needs obviously to be created multiple times. If you only ever call this singleton from your UI (and therefore only from the main thread), then the sample above is fine.
If you need access from multiple threads you need to put a lock around the +sharedInstance and +resetSharedInstance method, e.g.
+ (id)sharedInstance {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
}
+ (void)resetSharedInstance {
#synchronized(self) {
sharedInstance = nil;
}
}
This is quite a bit slower than the dispatch_once variant, but in practice it won't matter usually.
Yeah, but your singleton's sharedInstance method defines it as a static inside that method, and your final code sample is just setting a local variable (coincidentally also called shared) to nil, leaving the static inside sharedInstance unaltered. Thus you are just nil-ing a local pointer, not changing the static inside sharedInstance.
If you want to do what you're asking, you'll have to pull the static variable, shared, out of the sharedInstance method (and presumably write some reset method to nil it). Your sharedInstance method also can no longer rely upon dispatch_once, but rather have to check to see if that static is nil or not.
I did this. I'm not sure if it's the best way but it seemed to work fine.
static dispatch_once_t pred;
static MySingleton *shared = nil;
+(MySingleton *)sharedInstance {
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
+(void)clearSharedInstance {
shared = nil;
pred = nil;
}