Objective-c singleton creation - objective-c

Code sample 1:
+ (MyClass *)sharedInstance{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
code sample 2
+ (MyClass *)sharedInstance{
static MyClass *sharedInstance = nil;
if (!sharedInstance) {
sharedInstance = [[MyClass alloc] init];
}
return sharedInstance;
}
Are there any differences in the result of the above code samples ?

The first one is better as it prevents multiple threads from creating multiple instances of the Singleton class given the necessary circumstances are met.
E.g: Take the 2nd example.
+ (MyClass *)sharedInstance{
static MyClass *sharedInstance = nil;
if (!sharedInstance) {
sharedInstance = [[MyClass alloc] init];
}
return sharedInstance;
}
Suppose Theread1 executes the following LOC and then gives the handle to Thread2
if (!sharedInstance)
Now Thread2 executes the following LOC and then hands over the handle to Thread1
sharedInstance = [[MyClass alloc] init];
Now, since the if condition was met first by Thread1, Thread1 will continue and execute the following LOC as well
sharedInstance = [[MyClass alloc] init];
Now, you have 2 instances of MyClass created.
Therefore, the 1st approach is best. It will make sure the block within
dispatch_once(&onceToken, ^{
});
gets executed only Once!
However, if you ONLY access the Singleton via the Main Thread (UI thread), then the second scenario will also work.

Using dispatch_once() is faster and it performs something only once so if you access it twice from different threads there won't be any problems.

Related

Subclassing a singleton not working as expected

I'm writing a class that communicates with an API. I started by creating a SessionManager:
#interface SessionManager : AFHTTPSessionManager
+ (id)sharedManager;
#end
static NSString *const kBaseURL = #"https://myapi.com";
#implementation SessionManager
- (id)init {
self = [super initWithBaseURL:[NSURL URLWithString:kBaseURL]];
if(!self) return nil;
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.requestSerializer = [AFJSONRequestSerializer serializer];
return self;
}
+ (id)sharedManager {
static SessionManager *_sessionManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sessionManager = [[self alloc] init];
});
return _sessionManager;
}
#end
I wrote several classes that extend this SessionManager. One for every entity in the API: RestaurantManager, StreetManager and AreaManager. What happens, though, is that when I use one of them and then another, it will still use the first one.
NSArray *restaurants = [[RestaurantManager sharedManager] getRestaurants];
// restaurants contains all the restaurants
NSArray *streets = [[StreetsManager sharedManager] getStreets];
// streets still contains all the restaurants
Any ideas as to how to fix this?
You should override + (id)sharedManager methods in subclasses. Otherwise, they go to the same sharedManager method and interact with the same static SessionManager variable.

Dispatch_once singleton error objective c

I am relatively new to GCD, I am currently using it to create a singleton object in my application. After doing some research I found using GCD's dispatch_once() method is the best way to achieve the singleton design pattern. For some reason, my code is breaking and I can not figure it out for the life of me. Below, I have pasted my singleton creation/init code, and the responding error.
+(id)sharedErrorMapper {
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^
{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
-(id)init {
//creating the ErrorMap data structure
//currently loading in dummy JSON data..
self = [super init];
if (self != nil) {
NSError *error = [[NSError alloc] init];
NSData *resourceData = [[NSData alloc] initWithContentsOfFile:
#"/Users/acuram/Desktop/GitHubWorkspaces/ios-sdk-src/ios-here-sdk/PPHSDKTests/Resources"];
self.errorMap = [[NSDictionary alloc] init];
self.errorMap = [NSJSONSerialization JSONObjectWithData:resourceData options:kNilOptions error:&error];
}
return self;
}
After setting some breakpoints and doing some stack tracing, my code is breaking at the dispatch_once() function call. The error I get back is a "NSInvalidArgumentException", it complains that my data parameter is nil. I am pretty shocked because I followed a legit tutorial video on youtube to implement this, I am also looking at my companies code base and they seem to do it in a similar way....

dispatch once issue in ios7 mrc

In the iOS7 SDK and while using MRC, the following piece of code does not return the shared instance. On runtime it just hangs and it does not move in to the next line of code.
+(id)getInstance
{
static dispatch_once_t pred;
static IAPManager *inAppManager = nil;
dispatch_once(&pred, ^{
inAppManager = [[IAPManager alloc] init];
});
return inAppManager;
}
What is the reason for this anomaly? This is how I am calling
IAPManager *iapManager = [IAPManager getInstance];
if ([iapManager canMakePurchases]) {
[iapManager loadStore:proUpgradeProductId];
}else{
UIAlertView *aView = [[UIAlertView alloc]initWithTitle:#"" message:#"This device is not able or allowed to make payments" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[aView show];
}
The original getInstance method is absolutely fine (I would declare it as returning IAPManager*, but it doesn't make any difference to how it works). "static" variables are initialised once wherever they are.
The problem is most likely that getInstance is called from [[IAPManager alloc] init]. Calling dispatch_once from inside the dispatch_once is an instant deadlock. To find out, you just set a breakpoint in getInstance on the dispatch_once statement. It should be hit once during the first call, and then probably again, and the original call will be on the stack. Or just wait until it hangs, then check in the debugger where each thread is. You'll find a thread waiting for dispatch_once to finish.
Alternatively, it is possible that the init method just doesn't return. Maybe it does some network access that doesn't finish. To step into the code, set a breakpoint on the first (and only) line of the block, that is the [[IAPManager alloc] init] line. Once that breakpoint is reached, you can step through the code.
Diclare inAppManager object outside the method. and use the following code
static IAPManager *inAppManager = nil;
+(id)getInstance
{
if (nil != inAppManager) {
return inAppManager;
}
static dispatch_once_t pred;
dispatch_once(&pred, ^{
inAppManager = [[IAPManager alloc] init];
});
return inAppManager;
}
That may help you.
Thanks
Satya
Try this:
+(instancetype)getInstance
{
static id inAppManager;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
inAppManager = [[[self class] alloc] init];
});
return inAppManager;
}

alloc-init objects within +(void)initialize method to reuse them multiple times

I'm using a NSDateFormatter object (customized for specific purposes) multiple times. Since I'm not a objc expert, I figured out three different approaches to deal with it.
In the first one, I've created a NSDateFormatter category and customized the code there. This is common approach but each time I create such an object, this is put in the main autorelease pool. This behaviour, I think, is valid both for non-ARC and ARC code.
In the second instead, I've overridden the +(void)initialize method and put the customization code there. Here a simple example:
static NSDateFormatter* dateFormatter = nil;
+(void)initialize
{
dateFormatter = [[NSDateFormatter alloc] init];
// other code here
}
Finally, I set up a third approach using a lazy loading instantiation through properties like the following:
-(NSDateFormatter)dateFormatter
{
if(dateFormatter) return dateFormatter;
// alloc-init here
}
Said this, I would like to know what approach is the most suitable to deal with objects multiple times and if, using +(void)initialize in that manner, is correct.
Thank you in advance.
Both later methods are correct, but I believe you want to put them together!
static NSDateFormatter *sharedInstance = nil;
+ (NSDateFormatter *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[NSDateFormatter alloc] init];
}
return sharedInstance;
}
Note: Such classes are called singletons. Read more
Essentially, my favourite pattern is the one that mindw0rk has already given (I have up voted his answer). It has the advantage that you can put the method in a category on NSDateFormatter. I would modify it slightly thusly:
+ (NSDateFormatter *)sharedInstance {
static NSDateFormatter *sharedInstance = nil;
if (sharedInstance == nil) {
sharedInstance = [[NSDateFormatter alloc] init];
}
return sharedInstance;
}
so that you can't inadvertently reference sharedInstance without initialising it first.
If you have more than one shared instance, you can have a different method to get each one e.g.
+ (NSDateFormatter *)dateFormatterForFoo {
static NSDateFormatter *sharedInstance = nil;
if (sharedInstance == nil) {
sharedInstance = [[NSDateFormatter alloc] init];
}
return sharedInstance;
}
+ (NSDateFormatter *)dateFormatterForBar {
static NSDateFormatter *sharedInstance = nil;
if (sharedInstance == nil) {
sharedInstance = [[NSDateFormatter alloc] init];
}
return sharedInstance;
}
Or if each customised date formatter has its own subclass, they can each implement +sharedInstance to give back an object of the right class.
Or you can have a dictionary of date formatters:
+ (NSDateFormatter *)customisedFormatterForKey: (NSString*) key {
static NSDictionary *sharedInstances = nil;
if (sharedInstance == nil) {
sharedInstance = [[NSDictionary alloc] initWithObjectsAndKeys: ....];
}
return [sharedInstance objectForKey: key];
}
I have some comments on the -initialize approach.
You have to be a little bit careful about using -initialize. It's invoked once just before first use of the class. If you never use the class, it will never get invoked. So for your code to work, you have to make sure you send a message to NSDateFormatter or an instance of NSDateFormatter before you start using the shared instance dateFormatter. Note that sending a message to dateFormatter itself doesn't count. This is because it starts out nil and therefore doesn't have a class.

Objective-C: How to use memory management properly for asynchronous methods

I need to call a method that starts some asynchronous code
MyClass* myClass = [[MyClass alloc] init];
[myClass startAsynchronousCode];
Now I can't simply release it as this would cause an error since the code is still running:
[myClass release]; // causes an error
What is the best way to deal with the memory?
You could have -[MyClass startAsynchronousCode] invoke a callback:
typedef void(*DoneCallback)(void *);
-(void) startAsynchronousCode {
// Lots of stuff
if (finishedCallback) {
finishedCallback(self);
}
}
and then instantiate a MyClass like this:
MyClass *myClass = [[MyClass alloc] initWith: myCallback];
myCallback might look like this:
void myCallback(void *userInfo) {
MyClass *thing = (MyClass *)userInfo;
// Do stuff
[thing release];
}
How are you invoking the asynchronous code? If you use NSThread +detachNewThreadSelector:toTarget:withObject:, you'll find that the target object is retained by the thread until it terminates and then it is released. So you can release the object immediately after the asynchronous message.
e.g.
#implementation MyClass
-(void) startAsynchronousCode
{
[NSThread detachNewThreadSelector: #selector(threadMain:) toTarget: self withObject: nil];
}
-(void) threadMain: (id) anObject
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// do stuff
[pool drain];
}
#end
With the above, the following code is perfectly safe:
MyClass* myClass = [[MyClass alloc] init];
[myClass startAsynchronousCode];
[myClass release];
You must retain your myClass object internally in startAsynchronousCode method. And release it internally too after it finished.
This behavior used in NSURLConnection, UIAlertView and other async objects.
What I've always done is maintained an instance variable that points to the asynchronous object.
- (id)init {
myClass = [[MyClass alloc] init];
[myClass startAsynchronousCode];
}
- (void)myClassDidFinish:(MyClass *)myClass {
[myClass release];
}