I want to check for a valid network connection. I followed Apple's Reachability example and put my check in applicationDidFinishLaunching
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
{
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
}
// Override point for customization after application launch.
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];
//Check for connectivity
internetReach = [[Reachability reachabilityForInternetConnection] retain];
[internetReach startNotifer];
[self updateInterfaceWithReachability: internetReach];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
However, my app will crash sometimes with the error Application Failed to Launch in Time
I have posted my crash as an SO question here: Application Failed to Launch in Time
I'm not sure where I should perform the reachability check?
A Reachability check could take a significant amount of time (30 seconds or more) depending on network conditions. But if your app's UI does not respond for some number of seconds (much less than 30), the OS assumes that it is dead and kills it.
If you do your Reachability check in a background thread, not the UI thread, then your UI will stay responsive, and neither the OS nor the user will assume that your app has locked up or crashed.
In -applicationDidBecomeActive you may call a method in the background that uses the reachability code with -performSelectorInBackground:withObject:.
Related
I am checking it with
- (void)applicationWillEnterForeground:(UIApplication *)application
when it comes back to the app.
But this one doesn't detect when the user declines the call. Is there anyway to detect even when the user declines the call?
Maybe you could use the following notifications, in your case, the second one:
Add CoreTelephony.framework to your project and:
#import <CoreTelephony/CTCall.h>
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callReceived:) name:CTCallStateIncoming object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callEnded:) name:CTCallStateDisconnected object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(callConnected:) name:CTCallStateConnected object:nil];
I think what you want is to detect when the app is coming back into an active state.
There are two delegate methods for this:
applicationWillEnterForeground:
Tells the delegate that the application is about to enter the foreground.
- (void)applicationWillEnterForeground:(UIApplication *)application
and
applicationDidBecomeActive:
Tells the delegate that the application has become active.
- (void)applicationDidBecomeActive:(UIApplication *)application
more info in the documentation of UIApplicationDelegate
There isn't a way that I know of to tell when the call is declined. But this method is called when the user gets a call:
- (void)applicationWillResignActive:(UIApplication *)application {
}
Whenever there is a connection problem, a slow connection on 2G , etc., my app crashes with the following log:
What I can get from the log is, that it crashes on sendSynchronousRequest method of the NSURLConnection. How do I know what exactly is the problem, and how do I solve it?
I have put Reachability methods, given by Apple, but the return YES to both Internet reachability and Host reachability. It's just that the internet connection is very slow.
On Fast connections (Wifi), it works perfectly well.
Edit:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window setFrame:[[UIScreen mainScreen] bounds]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//singleton
u=[[U5 alloc]init];
m_tUSyncPersistableConfig = [[USyncPersistableConfig alloc] init] ;
m_commonObj = [[CommonClass alloc] init] ;
u.m_tUSyncPersistableConfig=m_tUSyncPersistableConfig;
u.commonObj = m_commonObj;
//register for push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
//load persisting data : from sqlite database
[u loadPreferences:m_tUSyncPersistableConfig];
window.rootViewController = tabBarController;
[window makeKeyAndVisible];
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"]) {
//first launch//setting some values
}else {
//not first launch
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"] || [u.m_tUSyncPersistableConfig.mUserName isEqualToString:#""] || !u.m_tUSyncPersistableConfig.mUserName)
{
// This is the first launch ever
//present login page
}
else
{
// app already launched
[[u commonObj] performSelectorInBackground:#selector(getAccountInfo) withObject:nil];
}
return YES;
}
I would strongly recommend moving away from synchronous NSURLConnection web requests. It's not recommended by Apple and is considered bad design. I suggest moving to asynchronous requests -- it might sidestep your problem, and you can handle errors with the NSURLConnection delegate method.
Running synchronous requests in background threads is fine in general.
But the crash report shows that the synchronous request is running on the main thread. So there is at least one location where you are not running it in the background thread. And on the main thread it will block the UI and the iOS watchdog process will notice this and kill the app on startup.
So make sure, that you are never ever using synchronous requests on the main thread!
You are saying that you are doing this, but maybe you are doing it wrong. Show the code that is actually calling the connection methods. If you symbolicate the crash report it will also show these locations in the frames 8 to 10 of the thread 0 stack trace.
I m new to the iOS. When i press home button in iPhone, application goes into suspend mode is what i know, in the program, how can i capture this event, and clear my local datas?
Kindly advice.
You can use the following method from within your app delegate:
- (void)applicationWillResignActive:(UIApplication *)application
Apple explains when this delegate method is called:
Sent when the application is about to move from active to inactive
state. This can occur for certain types of temporary interruptions
(such as an incoming phone call or SMS message) or when the user quits
the application and it begins the transition to the background state.
Inside your delegate, put the code you want to call inside of these. One fires every time you background the application and the other fires when you come back.
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
While you can implement the UIApplicationDelegate methods discussed by others, it is often more convenient (and arguably cleaner) to have objects that need to do clean up register themselves for the corresponding notifications:
UIApplicationDidEnterBackgroundNotification
UIApplicationWillResignActiveNotification
E.g.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myCleanupMethod:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
(If you go this route, don't forget to remove the observer when the observing object is deallocated.)
Use app delegate applicationWillResignActive method and UIBackgroundTaskIdentifier if needed. For example:
- (void)applicationWillResignActive:(UIApplication *)application {
UIBackgroundTaskIdentifier backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^(void) {
[application endBackgroundTask:backgroundTaskIdentifier];
//your cleanup code
}];
}
I'm planning to implement multi-task in my app.
I can see many methods here to do that in the AppDelegate like applicationWillResignActive, applicationDidEnterBackground, applicationWillEnterForeground, ...
But.... I don't see the way they should be used, nor why they are not in the ViewControllers... Nor what they are here for.
I mean : when the app enter in background, i don't know on which view my user is.
And back, when the app comes into foreground, how would I know what to do and what I may call, to update the view for example ?
I would have understood if those methods where in each view controller, but here, I don't see what they can be used for in a concrete way...
Can you help me to understand the way to implement things into those methods ?
Each object receive a UIApplicationDidEnterBackgroundNotification notification when the app goes in background. So to run some code when the app goes in background, you just have to listen to that notification where you want :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appHasGoneInBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
Don't forget to release the listener when you don't need to listen to it anymore :
[[NSNotificationCenter defaultCenter] removeObserver:self];
And best of the best, you can play the same way with the following notifications :
UIApplicationDidEnterBackgroundNotification
UIApplicationWillEnterForegroundNotification
UIApplicationWillResignActiveNotification
UIApplicationDidBecomeActiveNotification
They are not in any of your view controllers because iOS adopts a 'delegate' design pattern, where you can be assured that a method will fire upon a class (in this case, the App Delegate for your application) when required.
As a learning process, why don't you just put NSLog's in those methods to see when they're fired?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
NSLog(#"didFinishLaunchingWithOptions");
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
NSLog(#"applicationWillResignActive");
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
NSLog(#"applicationDidEnterBackground");
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of transition from the background to the active state: here you can undo many of the changes made on entering the background.
*/
NSLog(#"applicationWillEnterForeground");
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
NSLog(#"applicationDidBecomeActive");
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
NSLog(#"applicationWillTerminate");
}
How can I diagnose this error?
Application Specific Information:
MyApp failed to launch in time
Elapsed total CPU time (seconds): 4913.443 (user 3868.270, system 1045.173), 56% CPU
Elapsed application CPU time (seconds): 0.010, 0% CPU
Backtrace not available
Unknown thread crashed with unknown flavor: 5, state_count: 1
Binary Images:
0x2fe00000 - 0x2fe26fff dyld armv7 <a11905c8ef7906bf4b8910fc551f9dbb> /usr/lib/dyld
Here is my didFinishLaunching method:
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
{
NSLog(#"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
}
// Override point for customization after application launch.
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];
//Check for connectivity
internetReach = [[Reachability reachabilityForInternetConnection] retain];
[internetReach startNotifer];
[self updateInterfaceWithReachability: internetReach];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
You're probably doing a lot of setup work in your AppDelegate's application:didFinishLaunching method.
You should make sure this function exits as soon as possible. Any setup-work that takes time (network access for example) should be done asynchronously in your application. While this is going on, you can show a spinner to indicate to the user that the application is loading.
In order to add so information to Philippe Leybaert response.
If the application take to much time to start the main thread will be kill so the application will crash.
When you're using the simulator, it will not crash.
When you are using your iphone connected to xcode it will not crash.
When you send it for App Store it might be accepted if the Apple tester is using a fast iPhone
When your users on slow like iPhone 3S will crash
A way to test this issu before submitting is to deploy to testflight or with adhoc and install it on the slower device you want to support.
Just try to divide your application:didFinishLaunchingWithOptions: method code to different function calls and make those calls in background using the threads other then main and make sure that application:didFinishLaunchingWithOptions: method returns as soon as possible
you can use
dispatch_async(dispatch_get_main_queue(), ^{
//put your code
}
I have resolved the issue using this code !