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 ;)
+(Service *) sharedInstance
{
static LocationService *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ <<<< Crash
instance = [[self alloc]init];
});
return instance;
}
I am using the above shown code to create a singleton instance of service in my application. This is called from "AppDelegate application:willFinishLaunchingWithOptions:".
For most of the users, this code works fine. But for 2 users, the app crashes at "dispatch_once(&onceToken, ^{ " line.
They deleted the app and re-installed it. But they still see the issue. Only these 2 users are facing this issue. Others have never seen it. I have the .dsym, .crash and other relevant files to do further debugging. Just wanted to know how should I proceed with it? If someone has seen similar issue how did they proceed with fixing it?
Don't use self. Because self is not available before the initilization of class. Instead you can use class name as follows.
+(Service *) sharedInstance
{
static LocationService *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[Service alloc]init];
});
return instance;
}
In my app, when the user launched the app, I create an instance of a class in my AppDelegate and call a method in the class which compares all of the user's iOS contacts to find which ones are using my app, and puts those contacts into an NSMutableArray
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
GetContactClass *contact = [[GetContactClass alloc] init];
[contact getAllContacts];
...
}
GetContactClass.h
#property (retain, nonatomic) NSMutableArray *appContacts;
At the end of the getAllContacts method, I NSLog out appContacts and it works fine.
However, later in the app I try to set an NSMutableArray in a ViewController to equal appContacts, but I get a (null) array.
ViewController.m
self.searchableContacts = [[NSMutableArray alloc] init];
GetContactClass *contact = [[GetContactClass alloc] init];
self.searchableContacts = contact.appContacts;
What am I doing wrong here?
You're creating an entirely new instance which hasn't been asked to collect all contacts, so it hasn't stored them. By the look of the code the instance which has stored them has been destroyed. As you're running this on the main thread you might as well just ask the new instance to get contacts and delete the code for the old one. It's better however to run the contacts collection on a background thread and keep the result till you need it, in a retained instance variable.
If you want use this data in all app you must use a Pattern Design Singleton:
In objective-c:
#implementation Settings
+ (id)sharedInstance {
static Settings *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Other way is change retain to strong but this is a bad idea and put this property in appDelegate and call all times APPDelegate get property.
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.
While building my app, Marco Polo (getmarcopolo.com), I found that one of the most challenging parts of the app was pulling data from the server without slowing down the interface and without it crashing. I've got it settled now, and wanted to share my knowledge with any other developers having the same issue.
When pulling data from a server, there are a number of factors that need to be taken into consideration:
Data integrity - No data is ever missed from the server
Data persistence - Data is cached and can be accessed even when offline
Lack of interference with the interface (main thread) - Achieved using multithreading
Speed - Achieved using thread concurrency
Lack of thread collisions - Achieved using serial thread queues
So the question is, how do you achieve all 5?
I've answered this below, but would love to hear feedback on how to improve the process (with this example), as I feel it is not very easy to find in one place right now.
I'll be using the example of refreshing the marco's in the notification feed. I'll also be referring to Apple's GCD library (see https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html). First, we create a singleton (see http://www.galloway.me.uk/tutorials/singleton-classes/):
#implementation MPOMarcoPoloManager
+ (MPOMarcoPoloManager *)instance {
static MPOMarcoPoloManager *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
#end
This allows for us to call [MPOMarcoPoloManager instance] at any time, from any file, and access the properties in the the singleton. It also ensures that there is always only one instance of the marco polos. 'static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{' ensures thread stability.
The next step is to add the data structure we will be accessing publicly. In this case, add an NSArray for the marcos to the header file, as well as a public declaration of 'instance':
#interface MPOMarcoPoloManager : NSObject
+ (MPOMarcoPoloManager *)instance;
#property (strong, nonatomic) NSArray *marcoPolos;
#end
Now that the array and the instance are accessible publicly, it's time to ensure data persistence. We will achieve this by adding the ability to cache the data. The following code will
1. Initializes our serverQueue to the global queue, which allows multiple threads to run concurrently
2. Initializes our localQueue to a serial queue, which allows only one thread to be run at a time. All local data manipulation should be done on this thread to ensure no thread collisions
3. Gives us a method to call for caching our NSArray, with objects that conform to NSCoding (see http://nshipster.com/nscoding/)
4. Attempts to pull the data structure from the cache, and initializes a new one if it cannot
#interface MPOMarcoPoloManager()
#property dispatch_queue_t serverQueue;
#property dispatch_queue_t localQueue;
#end
#implementation MPOMarcoPoloManager
+ (MPOMarcoPoloManager *)instance {
static MPOMarcoPoloManager *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (id)init {
self = [super init];
if (self) {
_marcoPolos = [NSKeyedUnarchiver unarchiveObjectWithFile:self.marcoPolosArchivePath];
if(!self.marcoPolos) {
_marcoPolos = [NSArray array];
}
//serial queue
_localQueue = dispatch_queue_create([[NSBundle mainBundle] bundleIdentifier].UTF8String, NULL);
//Parallel queue
_serverQueue = dispatch_queue_create(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
}
return self;
}
- (NSString *)marcoPolosArchivePath {
NSArray *cacheDirectories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [cacheDirectories objectAtIndex:0];
return [cacheDirectory stringByAppendingFormat:#"marcoPolos.archive"];
}
- (BOOL)saveChanges {
BOOL success = [NSKeyedArchiver archiveRootObject:self.marcoPolos toFile:[self marcoPolosArchivePath]];
return success;
}
#end
Now that we have the structure of the singleton, It's time to add the ability to refresh our marco's. Add the declarations of refreshMarcoPolosInBackgroundWithCallback:((^)(NSArray *result, NSError *error)) to the header file:
...
- (void)refreshMarcoPolosInBackground:((^)(NSArray *result, NSError *error))callback;
...
Now it's time to implement the refresh. Notice that all server calls are performed on the serverQueue (which is parallel), and any data manipulation is done on the localQueue (which is serial). When the method is completed, we use what is called a C block (see https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html) to callback the result to the main thread. Any task that acts on a background thread should have a callback to the main thread to inform the interface that the refresh has completed (whether it be successful or not).
...
- (void)refreshMarcoPolosInBackground:((^)(NSArray *result, NSError *error))callback {
//error checking ommitted
//Run the server call on the global parallel queue
dispatch_async(_serverQueue, ^{
NSArray *objects = nil;
NSError *error = nil;
//This can be any method with the declaration "- (NSArray *)fetchMarcoPolo:(NSError **)callbackError" that connects to a server and returns objects
objects = [self fetchMarcoPolo:&error];
//If something goes wrong, callback the error on the main thread and stop
if(error) {
dispatch_async(dispatch_get_main_queue(), ^{
callback(nil, error);
});
return;
}
//Since the server call was successful, manipulate the data on the serial queue to ensure no thread collisions
dispatch_async(_localQueue, ^{
//Create a mutable copy of our public array to manipulate
NSMutableArray *mutableMarcoPolos = [NSMutableArray arrayWithArray:_marcoPolos];
//PFObject is a class from Parse.com
for(PFObject *parseMarcoPoloObject in objects) {
BOOL shouldAdd = YES;
MPOMarcoPolo *marcoPolo = [[MPOMarcoPolo alloc] initWithParseMarcoPolo:parseMarcoPoloObject];
for(int i = 0; i < _marcoPolos.count; i++) {
MPOMarcoPolo *localMP = _marcoPolos[i];
if([marcoPolo.objectId isEqualToString:localMP.objectId]) {
//Only update the local model if the object pulled from the server was updated more recently than the local object
if((localMP.updatedAt && [marcoPolo.updatedAt timeIntervalSinceDate:localMP.updatedAt] > 0)||
(!localMP.updatedAt)) {
mutableMarcoPolos[i] = marcoPolo;
} else {
NSLog(#"THERE'S NO NEED TO UPDATE THIS MARCO POLO");
}
shouldAdd = NO;
break;
}
}
if(shouldAdd) {
[mutableMarcoPolos addObject:marcoPolo];
}
}
//Perform any sorting on mutableMarcoPolos if needed
//Assign an immutable copy of mutableMarcoPolos to the public data structure
_marcoPolos = [NSArray arrayWithArray:mutableMarcoPolos];
dispatch_async(dispatch_get_main_queue(), ^{
callback(marcoPolos, nil);
});
});
});
}
...
You may be wondering why we would manipulate the data on a queue for something like this, but lets add a method where we can mark the marco as viewed. We don't want to have to wait for the server to update, but we also don't want to manipulate the local object in a manor that can cause a thread collision. So let's add this declaration to the header file:
...
- (void)setMarcoPoloAsViewed:(MPOMarcoPolo *)marcoPolo inBackgroundWithlocalCallback:((^)())localCallback
serverCallback:((^)(NSError *error))serverCallback;
...
Now it's time to implement the method. Notice that the local manipulation is done on the serial queue, then immediately calls back to the main thread, allowing the interface to update without waiting for a server connection. It then updates the server, and calls back to the main thread on a separate callback to inform the interface that the server save was completed.
- (void)setMarcoPoloAsViewed:(MPOMarcoPolo *)marcoPolo inBackgroundWithlocalCallback:(MPOOrderedSetCallback)localCallback
serverCallback:(MPOErrorCallback)serverCallback {
//error checking ommitted
dispatch_async(_localQueue, ^{
//error checking ommitted
//Update local marcoPolo object
for(MPOMarcoPolo *mp in self.marcoPolos) {
if([mp.objectId isEqualToString:marcoPolo.objectId]) {
mp.updatedAt = [NSDate date];
//MPOMarcoPolo objcts have an array viewedUsers that contains all users that have viewed this marco. I use parse, so I'm going to add a MPOUser object that is created from [PFUser currentUser] but this can be any sort of local model manipulation you need
[mp.viewedUsers addObject:[[MPOUser alloc] initWithParseUser:[PFUser currentUser]]];
//callback on the localCallback, so that the interface can update
dispatch_async(dispatch_get_main_queue(), ^{
//code to be executed on the main thread when background task is finished
localCallback(self.marcoPolos, nil);
});
break;
}
}
});
//Update the server on the global parallel queue
dispatch_async(_serverQueue, ^{
NSError *error = nil;
PFObject *marcoPoloParseObject = [marcoPolo parsePointer];
[marcoPoloParseObject addUniqueObject:[PFUser currentUser] forKey:#"viewedUsers"];
//Update marcoPolo object on server
[marcoPoloParseObject save:&error];
if(!error) {
//Marco Polo has been marked as viewed on server. Inform the interface
dispatch_async(dispatch_get_main_queue(), ^{
serverCallback(nil);
});
} else {
//This is a Parse feature that your server's API may not support. If it does not, just callback the error.
[marcoPoloParseObject saveEventually];
NSLog(#"Error: %#", error);
dispatch_async(dispatch_get_main_queue(), ^{
serverCallback(error);
});
}
});
}
With this setup, a refresh can be occuring the background, while setting a marco as viewed at the same time, while ensuring that the local model is not manipulated at the same time. While the necessity of the localQueue may not be obvious with only two methods, when having many different types of manipulation available, it becomes critical.
I use a dataManager that contains two sub managers, core data fetch manager and restkit manager, which maps to core data.
for example:
anywhereInApp.m
[dataManager getData: someSearchPrecate withCompletionBlock: someBlock];
dataManager.m
- (void) getData: somePredicate withCompletionBlock: someblock{
[self.coreDataManager fetchData: somePredicate withCompletionBlock: some block];
[self.restkitManager fetchData: somePredicate withCompletionBlock: some block];
}
and then core data manger runs on a thread to fetch data and executes completion block.
and reskitmanager runs a thread and executes completion block when http request and object mapping complete.
usually the completion block updates the data shown in a collection view.
only need to worry about old data getting removed from core data, but that's another story and can involve comparing the results from the two different calls and taking appropriate action. I try to picture a venn diagram of result sets and it all makes sense or I am too tired & drinking too good of beer.