dispatch once issue in ios7 mrc - objective-c

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;
}

Related

Objective-c singleton creation

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.

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....

addObjectsFromArray: not copying into global NSMutableArray

So here is a partial sample of the relevant code.
static NSMutableArray *radioInputArray;
static NSMutableArray *buttonsArray;
- (IBAction)lookForRadioButtons:(id)sender {
// NSLog(#"Testing");
NSError *error;
NSString *radiostr = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"getRadios" ofType:#"txt"] encoding:NSASCIIStringEncoding error: &error] ;
if (radiostr == nil)
{
NSLog (#"Error! %#", error);
}
else
{
NSLog(#"%#",radiostr);
NSString *radiotxt= [webView stringByEvaluatingJavaScriptFromString:radiostr];
NSLog(#"%#", radiotxt);
NSArray *myRadios = [radiotxt componentsSeparatedByString:#"::"];
[radioInputArray addObjectsFromArray:myRadios];
NSLog(#"%d", myRadios.count);
NSLog(#"Number of buttons in global radio array %d", radioInputArray.count);
NSLog(#"%d", scrollViewer.subviews.count);
}
}
So it throws no exceptions and seems to work properly except after addObjectsFromArray:, my count in the global NSMutableArray is 0 (the count in the myRadios = 56). I am pretty sure they should be equal at this point but are not. I have declared my NSMutableArray up near the top so that it can be globally accessed. Am I missing something such as allocating and initializing this? Does it not do that automatically like in C#? Again, this is my first foray into the Objective-C world from Windows programming so please be gentle yet feel free to be critical.
Your two global arrays are not initialized.
The lines
static NSMutableArray *radioInputArray;
static NSMutableArray *buttonsArray;
just define the two variables as pointers to NSMutableArray, so you need to get them to point at an actual instance of the class NSMutableArray.
Somewhere in your initialization code, or through an accessor (best if a class method), you should set the variables to an empty, newly allocated NSMutableArray.
Here is a way to do it:
+ (NSMutableArray*)radioInputArray
{
if (!radioInputArray) {
radioInputArray = [[NSMutableArray alloc] init];
}
return radioInputArray;
}
Then use the accessor in your code instead of the global variable.
It may happen if your radioInputArray is nil,
you didn't initialize the array
you need to add
[[radioInputArray alloc] init];
before you do anything with radioInputArray
Good place for initialising object is "init" method in Global class
Ex.
-(id)init
{
if (self=[super init]) {
self.globalAllArtworkArray=[[NSMutableArray alloc] init];
self.globalCollectionArray=[[NSMutableArray alloc] init];
self.globalLookbookArray=[[NSMutableArray alloc] init];
}
return self;
}
+(ASNGlobalClass *)shareManager
{
static ASNGlobalClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

Error trying to assigning __block ALAsset from inside assetForURL:resultBlock:

I am trying to create a method that will return me a ALAsset for a given asset url. (I need upload the asset later and want to do it outside the result block with the result.)
+ (ALAsset*) assetForPhoto:(Photo*)photo
{
ALAssetsLibrary* library = [[[ALAssetsLibrary alloc] init] autorelease];
__block ALAsset* assetToReturn = nil;
NSURL* url = [NSURL URLWithString:photo.assetUrl];
NSLog(#"assetForPhoto: %#[", url);
[library assetForURL:url resultBlock:^(ALAsset *asset)
{
NSLog(#"asset: %#", asset);
assetToReturn = asset;
NSLog(#"asset: %# %d", assetToReturn, [assetToReturn retainCount]);
} failureBlock:^(NSError *error)
{
assetToReturn = nil;
}];
NSLog(#"assetForPhoto: %#]", url);
NSLog(#"assetToReturn: %#", assetToReturn); // Invalid access exception coming here.
return assetToReturn;
}
The problem is assetToReturn gives an EXC_BAD_ACCESS.
Is there some problem if I try to assign pointers from inside the block? I saw some examples of blocks but they are always with simple types like integers etc.
A few things:
You must keep the ALAssetsLibrary instance around that created the ALAsset for as long as you use the asset.
You must register an observer for the ALAssetsLibraryChangedNotification, when that is received any ALAssets you have and any other AssetsLibrary objects will need to be refetched as they will no longer be valid. This can happen at any time.
You shouldn't expect the -assetForURL:resultBlock:failureBlock:, or any of the AssetsLibrary methods with a failureBlock: to be synchronous. They may need to prompt the user for access to the library and will not always have their blocks executed immediately. It's better to put actions that need to happen on success in the success block itself.
Only if you absolutely must make this method synchronous in your app (which I'd advise you to not do), you'll need to wait on a semaphore after calling assetForURL:resultBlock:failureBlock: and optionally spin the runloop if you end up blocking the main thread.
The following implementation should satisfy as a synchronous call under all situations, but really, you should try very hard to make your code asynchronous instead.
- (ALAsset *)assetForURL:(NSURL *)url {
__block ALAsset *result = nil;
__block NSError *assetError = nil;
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[[self assetsLibrary] assetForURL:url resultBlock:^(ALAsset *asset) {
result = [asset retain];
dispatch_semaphore_signal(sema);
} failureBlock:^(NSError *error) {
assetError = [error retain];
dispatch_semaphore_signal(sema);
}];
if ([NSThread isMainThread]) {
while (!result && !assetError) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
else {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
dispatch_release(sema);
[assetError release];
return [result autorelease];
}
You should retain and autorelease the asset:
// ...
assetToReturn = [asset retain];
// ...
return [assetToReturn autorelease];

Initialising a static variable in Objective-C category

I was trying to create a static variable to store a dictionary of images. Unfortunately, the best way I could find to initialise it was to check in each function that used the variable. Since I am creating this variable inside a category, I can't just initialise it inside the initialiser. Is there a neater way of initialising navigationBarImages?
static NSMutableDictionary *navigationBarImages = NULL;
#implementation UINavigationBar(CustomImage)
//Overrider to draw a custom image
- (void)drawRect:(CGRect)rect
{
if(navigationBarImages==NULL){
navigationBarImages=[[NSMutableDictionary alloc] init];
}
NSString *imageName=[navigationBarImages objectForKey:self];
if (imageName==nil) {
imageName=#"header_bg.png";
}
UIImage *image = [UIImage imageNamed: imageName];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
//Allow the setting of an image for the navigation bar
- (void)setImage:(UIImage*)image
{
if(navigationBarImages==NULL){
navigationBarImages=[[NSMutableDictionary alloc] init];
}
[navigationBarImages setObject:image forKey:self];
}
#end
__attribute__((constructor))
static void initialize_navigationBarImages() {
navigationBarImages = [[NSMutableDictionary alloc] init];
}
__attribute__((destructor))
static void destroy_navigationBarImages() {
[navigationBarImages release];
}
These function will be called automatically when the program starts and ends.
Consider this approach,
static NSMutableDictionary *navigationBarImages()
{
static NSMutableDictionary *dict = NULL;
if(dict == NULL)
{
dict = [[NSMutableDictionary alloc] init];
}
return [[dict retain] autorelease];
}
then whenever you woulde use navigationBarImages, replace it with navigationBarImages(), like this:
change
NSString *imageName=[navigationBarImages objectForKey:self];
to
NSString *imageName=[navigationBarImages() objectForKey:self];
If the function call overhead bothers you, maybe use a temporary variable to catch the return of navigationBarImages(),
NSMutableDictionary *dict = navigationBarImages();
[dict doSomething];
[dict doSomething];
The drawback is once you called navigationBarImages(), the instance of NSMutableDictionary got created, then it'll never get chance to dealloc until the end of the program.
All you need is to set your static once at a known point before it is used. For example, you can set an NSApplication delegate and have it do the work in -applicationDidFinishLaunching:
One option is to use C++. Change the file's extension to .mm and replace = NULL with [[NSMutableDictionary alloc] init].
You could add +initialize in the .m file of your category — you'll just need to make sure you're not smashing an existing implementation or you'll get general wonkiness. (Obviously, you can be sure of this if you wrote the code, but with third-party code, this is probably not the best approach.)