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.
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'm trying to call a dispatch_async queue inside a for-loop. A new queue is added for every loop.
queue1 = dispatch_queue_create("com..queue1", DISPATCH_QUEUE_CONCURRENT);
for(NSDictionary *dictInfo in dataArray) {
dispatch_async(queue1,^(void) {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
HeaderValueGenerator *valueGenerator = [HeaderValueGenerator instance] ;
valueGenerator.apiPath = #"path";
valueGenerator.request = request;
[request addValue:[valueGenerator createSignature] forHTTPHeaderField:#"X-Authorization-Client"];
//request is used to call the server. (asynchronous call and hence inside dispatch_async)
}
}
The request is used to make asynchronous call to the server. The server responds with mismatched signature. The createSignature method is not run for some of the requests.
The following is a thread safe singleton. I'm using the singleton as a shared resource for various NSURLRequest for different API calls. So I can't be defining it in all the request objects rather call them using this singleton.
HeaderValueGenerator.h
#import <CommonCrypto/CommonHMAC.h>
#interface HeaderValueGenerator : NSObject
#property (nonatomic,strong) NSString *apiPath;
#property (nonatomic,strong) NSMutableURLRequest *request;
+ (HeaderValueGenerator *)instance;
- (NSString *)createSignature;
#end
HeaderValueGenerator.m
+ (HeaderValueGenerator *)sharedInstance {
static HeaderValueGenerator *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return sharedInstance;
}
- (NSString *)createSignature {
// String hashing and data encoding the header values for special header fields
return SignedString;
}
When this program runs through the for loop, a few of the loops doesn't execute the createSignature method. As a result I get a bad response from the server. Is there a better way to use dispatch_async?
Is there a deadlock?
EDIT
-(void)createSignature{
#synchronized(self) {
// ... do stuff ...
}
}
Will this help? Defining the method inside synchronized(self)?
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.
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.