Why does not executing the following code cause it to crash? - ios

I have an app that uses Admob. But since I am supporting versions of iOS 5 and above, I make sure that I don't call Admob code in versions below iOS 6 by doing the following:
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_5_1) {
int j = 2;
j++; //This is just some code so I can use breakpoints for testing.
NSLog(#"Google Mobile Ads SDK version: %#", [GADRequest sdkVersion]); //Commenting out the line prevents the crash
}
I am testing on iOS 5.1.1. Now if I comment out the NSLog, line, the app works without problem. But if I uncomment it the app crashes almost immediately within the main method:
int retVal = UIApplicationMain(argc, argv, nil, #"AppController");
I guess its not crashing when it is commented out because the compiler "optimises out" the code since its not used. But then what is the correct way to make sure the code isn't used, and the app doesn't crash ?
EDIT: I edited the code, the if block is not optimised out:
int j = 2;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_5_1) {
j++; //This is just some code so I can use breakpoints for testing.
NSLog(#"Google Mobile Ads SDK version: %#", [GADRequest sdkVersion]); //Commenting out the line prevents the crash
}else{
j--;
}
NSLog(#"%d",j);
The output is "1", so the code in the else block executes. So even thought the function call [GADRequest sdkVersion] is not made, why does it crash ? Again, if I comment out the function call the app does not crash.

One possibility that is consistent with what you're describing is that linking to AdMob causes the crash. Sending a message to the GADRequest class in your code causes it to link to the GADRequest class, whereas if you didn't, it wouldn't link to it.
Why does linking to AdMob cause the crash? Most likely it's because AdMob links to several system frameworks, some of which may not exist on iOS 5 (e.g. AdSupport framework), so when it tries to dynamically link to them on app startup, the dynamic linker crashes.
I'm not sure what you can do. Maybe you can try explicitly linking to the system frameworks that AdMob use as "optional" in Xcode? (I haven't tested it.)
Otherwise, you could downgrade to a version of AdMob that supports iOS 5 (according to the release notes, any version before 7 should do).

I dont know why it crashes - but don't support iOS 5. It is pointless. The iOS market split is something like 20% iOS7, 80% iOS8. You cannot buy iOS5 phones, and you cannot install or, or even release apps for it.

Related

What happens if I use LAPolicyDeviceOwnerAuthentication on iOS 8?

In my app, I would like to know if the user has setup a passcode or fingerprint (touchID). There's a pretty easy method just for that: [LAContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:error].
However, Apple's docs say LAPolicyDeviceOwnerAuthentication is only available on iOS9 and above. I would rather not crash iOS 8 users without explanation, even if it is getting older. The thing is, I've tried it on an iOS8.4 simulator, and it seems to compile and just work.
What ill effects can happen if I use LAPolicyDeviceOwnerAuthentication on iOS 8?
I use code similar to this:
LAPolicy localAuthPolicy = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
if (![[UIDevice currentDevice].systemVersion hasPrefix:#"8."]) {
localAuthPolicy = LAPolicyDeviceOwnerAuthentication;
}
This ensures I only use LAPolicyDeviceOwnerAuthentication on iOS 9 and later.
It's undocumented what actually happens on an iOS 8 device when you attempt to use LAPolicyDeviceOwnerAuthentication. It's very unlikely anything will crash but the authentication may return NO due to an unknown value or it may succeed because iOS 8 only had one valid value and it may not do any checking.
Unfortunately Objective-C doesn't provide any runtime checks for valid enum values like you can do with constants, methods, and classes.
If you use LAPolicyDeviceOwnerAuthentication on anything below iOS 9, the app will crash. That is what happened to my app when I didn't realize that this was not available on anything below iOS 9, but my app supported iOS 8.x as its minimum supported OS version.

XCode setting to see code which won't work on previous OS versions

I've written an app specifically for iOS7, and am now attempting to make it work for iOS6.
I'd really like a setting to enable warnings which highlight lines of code which won't work on iOS6. i.e. any calls to code which ONLY work on iOS7.
That way I can immediately identify any lines of code which I need to attend to before catching them during debugging.
Does this even exist?
There is two option to deal with this.
Use MJGAvailability, a drop in header file and it will make warnings if a selector is "too new".
Buy Delpoymate, it can scan your Xcode project and show you any incompatible calls.
If you use an older Xcode next to the newest, than use this snippet:
if ([self respondsToSelector:#selector(newSelector)]){
#if __IPHONE_7_0
[self newSelector];
#endif
} else {
[self oldSelector];
}
There is no way of getting a warning to appear and even if there was how would the IDE now that you would have done something to handle it like the below
if([myObject respondsToSelect:#selector(myiOS7SelectorOnly)]) {
[myObject myiOS7SelectorOnly];
}
It works the other way if you where developing an app for iOS7 and you used a deprecated method that iOS7 API doesn't use any more it would give you a warning but not the other way you will have to wait for it to turn around and crash and throw an unrecognised selector exception.
At some point I had 2 Xcode installed - Xcode 4 and Xcode 5. Xcode 4 did not have API for ios7 and it was showing all incompatibilities.
But I don't know where can you find XCode4 now and will it still show errors in ios7 code or not?
At least you can try this way.

iOS 7 UIWebView not rendering

I'm porting my app to iOS 7 and I have a problem with UIWebView in iOS 7.
I load local html string in it with this code:
NSURL *baseURL = [NSURL fileURLWithPath: DOCUMENTS_DIRECTORY];
[self.descWebView loadHTMLString:html baseURL:baseURL];
It works perfectly on iOS 6 and prior but on iOS 7 it doesn't rendering and the UIWebView is still white. And this message appears in console:
void SendDelegateMessage(NSInvocation *): delegate
(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)
failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
Thanks for your replies.
As mentioned by #zaplitny, I had to update Crittercism to the latest version (4.1.0) for this problem to go away.
There was a problem with older version of the Crittercism library which caused this. As others have alluded to in comments, this bug was fixed in the 4.3.1 version of the Crittercism SDK.
https://app.crittercism.com/downloads/release_notes/ios/4.3.1 :
fix: Workaround for apps experiencing UIWebViews failing to load data
on first launch when running on iOS 7. This only occurs in apps that
subclass UIWebView, and Crittercism has filed a bug report with Apple.
Note - Be aware that while your application may not directly subclass
UIWebView, this is done in many common 3rd party libraries such as the
Google AdMob and Millenial Media SDKs.
For those of us who updated Crittercism to the version 4.1.2 hoping that it would solve the issue but it didn't. I can offer quite an ugly but simple solution: create and initialize UIWebView before calling [Crittercism enableWithAppID:#"***...***"];
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
...
UIWebView* fakeWebView = [[[UIWebView alloc] initWithFrame:CGRectMake(-1, -1, 1, 1)] autorelease];
[fakeWebView loadHTMLString:#"<!DOCTYPE HTML><html><body>I need Crittercism</body></html>" baseURL:nil];
[mainViewController.view addSubview:fakeWebView];
[Crittercism enableWithAppID:#"***...***"];
...
}
This trick allowed me not only to get rid of a described problem, but also slightly speed up the first initialization of a real UIWebView.
I had this error appearing trying to display admob ads, when ever crittercism was enabled I would get that error in the logs, incidentally the ads were not displaying either.
To fix it, I disabled crittercism instrumentation, this might not be an option for everyone.
[Crittercism enableWithAppID:#"your_app_id" andDelegate:nil andURLFilters:nil disableInstrumentation:YES];
If not simply creating a webview (You don't need to add it as a subview) as suggested by others seems to work for me as well.
[[UIWebView alloc] initWithFrame:CGRectMake(-1, -1, 1, 1)]
[Crittercism enableWithAppID:#"your_app_id"];
Try product --> clean. It can't hurt. When you run an app it will only replace/compile the files that changed. Some times the xCode bugs up and doesn't compile a changed file. Product clean deletes old versions of the compiled code so next time you build it will have been all from the last compile. Again you have nothing to lose by doing it.
I am seeing the same problem you are. I have tried:
moving the load request from the viewDidLoad to the viewWillAppear and viewDidAppear, this did not help anything
tried reloading the webview after the load request was made. still nothing
tried changing the URL creation from URLWithString to fileURLWithPath and still nothing
What is even more strange is that none of the delegate methods fire when the page doesnt load. it is almost as if the web view doesnt even attempt to load the page. Yet, like you said, if you close the app from the multitask view and reopen it, everything works fine.
were you able to figure out a way around this or found a solution?
I had similar issues with my PhoneGap application on IOS7, i had to Redraw the UI of the page on "viewDidAppear" or "Pageshow" using the below code and this worked for me.
$(".cls_div_page_content").redraw();
jQuery.fn.redraw = function() {
return this.hide(0, function(){$(this).show()});
};
many times this error can come in case u are using something that is not available in that particular iOS version..
for example
NSString *test=#"test this";
[test containsString:#"test"];
use of containsString in iOS 7.1 will give you the same following error, but it will work fine in iOS 8.0,
void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:)
failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
I ran into this issue too. It seems the problem is caused when certain 3rd party libraries are linked, but I am not even sure exactly which one was responsible in my case. I didn't have Crittercism in my app.
What fixed it for me was the suggestion I found here on Apple's Dev Forum to instantiate a UIWebView early.
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// In a severe case of WTF: some 3rd party libs (exact culprit unknown) can cause webviews to stop
// showing anything on iOS 7, and instead have console warnings every 10 seconds that look like:
// void SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
// Just instantiating an UIWebView before any of the 3rd party libs kick in is enough to fix it.
// Don't know why, but it works.
if (SYSTEM_VERSION_LESS_THAN(#"8.0")) {
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
webView.delegate = nil; // Do something with webView to silence warning
}
return YES;
}
For those who are using Parse SDK with the 1.6.x version under iOS7/iOS8 and subclass UIWebView, same problem will appear if you are using PFInstallation saveInBackground method.
Solution is to delay call saveInBackground, e.g.:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[currentInstallation saveInBackground];
});

Release AVAudioPlayer in iOS4/iOS5 giving EXC_BAD_ACCESS error

EDIT: Updated my device (and deployment target) from iOS 4.3.5 to iOS 5.1.1 and still has the same issue
Having a problem releasing a class member AVAudioPlayer to play another sound after playing a sound.
This only seems to be a problem on one of my devices, a 3rd generation iPod Touch running iOS 4.3.5/5.1.1.
My 4th and 5th generation devices running iOS 6 run just fine.
[audio release];
audio = nil;
#try
{
audio = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if ((audio != nil) && (!error))
{
audio.delegate = (id)self;
audio.volume = gVolume/10;
[audio play];
}
else
{
[audio release];
audio = nil;
}
}
#catch (NSException *exception)
{
[audio release];
audio = nil;
}
First time through it plays just fine, but when this code executes a second time to play another sound, it gives an EXC_BAD_ACCESS error, which does not happen on my 4th/5th generation devices.
I purposely delay the release until I need to play another sound in order to give the play time to perform.
Tried working with AVAudioPlayerDelegate but that didn't solve the problem, nor does calling:
[audio prepareToPlay];
I do initialize audio to nil in viewDidLoad, and clean up in viewDidUnload and dealloc.
Was having a lot of memory leak issues but this version of the code seemed to have solved that.
Thanks to the comment above, and the failure of all my other ideas, I went ahead and took advantage of ARC.
I didn't want to refactor my entire project to start using ARC, so I rewrote a new class to handle all of my audio needs and set some compiler flags (-fobjc-arc) to enable ARC just for that file.
Not exactly sure what I was doing wrong before, but the system seems to be much better at managing memory than I am, and I'm happy to let it solve all my problems.
EDIT 2:
Apparently Apple did finally fix their memory leak so I went back to my ARC solution which works fine for both iOS 5 and iOS 6.
EDIT:
I may have been a little premature.
While implementing ARC for this was helpful in general, this specific problem goes deeper.
Apparently, there is a leak in Core Foundation for iOS 6.
Leak from NSURL and AVAudioPlayer using ARC
Memory Leak - NSString & NSURL
Using ARC, it works fine on my Gen 3 iOS 5 device, but leaks significantly for Gen 4/5 iOS 6.
Without ARC, Gen 4/5 iOS 6 works fine, but Gen 3 iOS 5 crashes.
I ended up making two versions of my new class, one using ARC and one not, and checking the system version at runtime [[UIDevice currentDevice] systemVersion] to determine which version to use.
It may be a little clumsy, but does allow me to support the Gen 3 devices. If Apple ever fixes their problem I can return to a single version at that time.

EXC_BAD_ACCESS in device, not in simulator

I have implemented adwhirl in my project. I have implemented it previously in my projects, so I just incorporated it into my current project from my previous.
- (UIViewController *)viewControllerForPresentingModalView {
{
return self;
}
I had used this in my previous projects..since my window.rootvviewcontroller was self only. But in my current project there are many screens on which I am showing ads, so I have used:
- (UIViewController *)viewControllerForPresentingModalView {
{
return return [[(AppDelegate *)[[UIApplication sharedApplication] delegate] window] rootViewController] ;;
}
The main problem is the program was crashing, and still is. At first everything was okay: iads test ads loaded up, but it crashed rarely. I soon understand it was because of Admob. It crashed rarely because admob ads were not loaded most of the time.
Now searching for these crashes, I came across a point that since I have made the project in Xcode 4.2 rather than my previous projects Xcode 4.0 there were strong attributes in my window and view controller. I removed it.
Now the problem is in simulator it doesn't crash but it crashes in device.
The error is after I have added adview as a subview and it has - (UIViewController *)viewControllerForPresentingModalView went through this function but before adWhirlDidReceiveAd method.
The actual crash is [GADRequestPrivate spamSignals] EXC_BAD_ACCESS.
Below answer has already earned bounty for me :) ..... you can try for your problem...
Link : Getting to the bottom of crash
I found one of the best way to Debug the code for Crash. Follow the link for Debugging technique:
http://www.cocoadev.com/index.pl?DebuggingAutorelease
You need to analyze your Console very carefully to see actually why the Crash occurs. This helped me in almost all of the Code that are without ARC enabled.
I recommend you analyze your project and look for memory leaks and zombies. It seems like you are sending a message to a released object which causes the invalid memory access. The zombies detection cannot be run on the device, but you can run it on the simulator. Take a look at Xcode Instruments - Enable NSZombie Detection? Where is it?
Hope it helps.
Even if this happens in proprietary Adwhirl code, you can learn a lot by turning on all the debugging flags as specified, for example, in How to break on __NSAutoreleaseNoPool. This answer discusses lots of debugging flags, not just autorelease pool ones.

Resources