if write something in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(#"Starting point 1");
}
main.m
int main(int argc,char * argv[])
{
......
NSLog(#"Starting point 0");
}
Which one is more useful main.m or appDelegate.m one and in which scenerio.
This is an interesting article that explains the app launch sequence.
http://oleb.net/blog/2011/06/app-launch-sequence-ios/
As a resume of the article the conclusion is:
Besides application:didFinishLaunchingWithOptions:, there are several more entry points for custom code during the launch sequence (none of which are usually needed):
Directly in main() before UIApplicationMain() is called.
The init method of a custom UIApplication subclass.
The initWithCoder: or awakeFromNib methods of our application delegate if it is created from a NIB file (the default).
The +initialize methods of our application delegate class or a custom UIApplication subclass. Any class receives an +initialize message before it is sent its first message from within the program.
Note that this sequence only happens at the actual launch of an app. If the app is already running and simply brought back from the background, none of this occurs.
You should use your UIApplicationDelegate, not the main.m.
The didFinishedLaunching method is a good (but not the only) starting point.
Only there your are sure all the iOS specific code is loaded correctly.
In the main the load could have had an error, the line would be executed in the main but not in the didFinishedLaunching method.
The main() method is the very first thing that is called in terms of iOS applications however it is a general rule never to touch the main() function in iOS programming.
The
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions
occurs after a successful launch of the app and should be used for any processes you need to do at the start of the application.
Related
I have joined in a old project and I found this line
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
signal(SIGPIPE, SIG_IGN);
....
}
I have found in docs this:
/*
* For historical reasons; programs expect signal's return value to be
* defined by <sys/signal.h>.
*/
But I'm still confused as to what the purpose of that line is.
From Apple's documentation:
When a connection closes, by default, your process receives a SIGPIPE signal. If your program does not handle or ignore this signal, your program will quit immediately.
Ignore the signal globally with the following line of code:
signal(SIGPIPE, SIG_IGN);
I have got requirement in one of my projects where user is asking to save data locally in case of sudden app crashes. Its form based app so user fill lots of data in form and if app crashes suddenly then user lost all data entered.
App is using Core Data to save data locally.
There is a point where we save entered data in core data but not during every second user fills data.
Also if app crashes core data also vanishes.
In fact, if your app crash, the callback :
- (void)applicationWillTerminate:(UIApplication *)application
will not be called. This one is only called if for some reasons the system need to shutdown your app (usually because resources are rare or because your background job is still doing work after the maximum time allowed) or if you are on < iOs 4. You don't have any way to know when your app will crash (but when you relaunch the app, you can know if it had crashed).
So for your particular case you have two solutions :
Use either a NSTimer with a quick firing rate, or call a fonction each time you edit a field and update the core-data context then save it on disk.
NSError *error = nil;
[managedObjectContext save:&error]
Did you set a persistentStoreCoordinator on your context ? If no, core-data will never persist your data on disk.
Crashes don't appear out of nowhere, find the place(s) where crashes might happen and fix it or if you can't, use a try-catch to keep your app running (but please, try not to do that...).
Hope this help
You can implement a HandleException to catch all exceptions that crash your application.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//for uncaughted exceptions
NSSetUncaughtExceptionHandler(&HandleException);
struct sigaction signalAction;
memset(&signalAction, 0, sizeof(signalAction));
signalAction.sa_handler = &HandleSignal;
sigaction(SIGABRT, &signalAction, NULL);
sigaction(SIGILL, &signalAction, NULL);
sigaction(SIGBUS, &signalAction, NULL);
//and more if you need to handle more signals
//another setup ...
return YES
}
#pragma mark crash management
void HandleException(NSException *exception) {
NSLog(#"[FALTAL] App crashing with exception: %#", exception);
//try to save your DB here.
}
void HandleSignal(int signal) {
//try to save your DB here.
}
#pragma -
However, I don't know about how many time you will have before application exits. But I suppose that you will have enough time to do the DB-backup task.
In particular case you can should use, try catch block, (but not) everywhere.
try {
//write your code
}catch(NSException *e){
//See what's the error
}finally{
//Save your context
}
This it the best solution in my thinking. However you can create a NSTimer which executes a method at some reasonable seconds where you can hold and save your context.
You can also save your context in AppDelegate's method like (if you're targeting iOS 4.0 and above and if your app was exit by iOS it self for some reason),
- (void)applicationWillTerminate:(UIApplication *)application{};
below method will always call when your app goes in background,
- (void)applicationDidEnterBackground:(UIApplication *)application{};
Use
(void)applicationWillTerminate:(UIApplication *)application
delegate method of AppDelgate to save your data in core data.
One question and one issue:
I have the following code:
- (void) registerForLocalCalendarChanges
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(localCalendarStoreChanged) name:EKEventStoreChangedNotification object:store ];
}
- (void) localCalendarStoreChanged
{
// This gets call when an event in store changes
// you have to go through the calendar to look for changes
[self getCalendarEvents];
}
These methods are in a class/object called CalendarEventReporter which contains the method getCalendarEvents (in the callback).
Two things:
1) If the app is in the background the callback does not run. Is there a way to make it do that?
2) When I bring the app back into the foreground (after having changed the calendar on the device) the app crashes without any error message in the debug window or on the device. My guess is that the CalendarEventReporter object that contains the callback is being garbage-collected. Is that possible? Any other thoughts on what might be causing the crash? Or how to see any error messages?
1) In order for the app to run in the background you should be using one of the modes mentioned in the "Background Execution and Multitasking section here:
uses location services
records or plays audio
provides VOIP
services
background refresh
connection to external devices
like through BLE
If you are not using any of the above, it is not possible to get asynchronous events in the background.
2) In order to see the crash logs/call stack place an exception breakpoint or look into the "Device Logs" section here: Window->Organizer->Devices->"Device Name" on left->Device Logs on Xcode.
To answer your first question, take a look at https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
What I did to get code running in the background is to do something like
In the .h file
UIBackgroundTaskIdentifier backgroundUploadTask;
In the .m file
-(void) functionYouWantToRunInTheBackground
{
self.backgroundUploadTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
//code to do something
}
-(void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUploadTask];
self.backgroundUploadTask = UIBackgroundTaskInvalid;
}
The code above I pretty much learned from objective c - Proper use of beginBackgroundTaskWithExpirationHandler
As for your second question, you should set a breakpoint where code is supposed to run when you bring the app back to the foreground. No one can figure out why an app crashes if not given enough code or information.
The solution to the second part of the question was to raise the scope of the object containing the callback code. I raised it to the level of the containing ViewController. This seems to work. I still can't figure out how to raise the Notification (i.e. execute the call back) if the notification comes while the app is in the background/suspended. This prevented the object containing the callback from being cleaned up.
In trying to implement the Google Analytics SDK for iOS, I've run into two brick walls.
The first one is that after executing this code in application:DidFinishLaunchingWithOptions:
[[GANTracker sharedTracker] startTrackerWithAccountID:#"UA-XXXXXXX-YY"
dispatchPeriod:10
delegate:self];
[[GANTracker sharedTracker] setDebug:YES];
.. and then trying to track anything or call dispatch, no debug messages are logged whatsoever. I've added NSLog lines before and after tracking calls and the code is definitely being reached.
Secondly, when I do try and do a manual dispatch, it returns NO. All the other issues I've seen online are where dispatch returns YES but it's somehow not going through properly. What does one do if dispatch actually returns NO?
I've tried adding an NSError * reference to the track methods and those actually succeed (no error, function returns YES). But the events are definitely not being periodically dispatched, since we're seeing nothing on the GA account more than 24 hours later.
EDIT: I've also got NSLog calls in both of the delegate methods (hitDispatched: and trackerDispatchDidComplete:eventsDispatched:eventsFailedDispatch:), and neither of those are being called either.
i think you should check this to delegate method of GANTracker
- (void)trackerDispatchDidComplete:(GANTracker *)tracker
eventsDispatched:(NSUInteger)hitsDispatched
eventsFailedDispatch:(NSUInteger)hitsFailedDispatch{
//print or check number of events failed or success
}
//Delegate is set to 'nil' instead of class instance which implements the delegate methods.
[[GANTracker sharedTracker] startTrackerWithAccountID:#"UA-XXXXXXX-YY"
dispatchPeriod:10
delegate:nil];
In your case, assuming that UIApplicationDelegate may be implementing GANTrackerDelegate, the message call should set delegate as ' self '.
Cheers!! Amar.
Possibly the dispatch is relying on the calling thread's run loop - Is it possible you are running this from a secondary thread, one which might not exist by the time the dispatch is suppose to call you back?
You've not enabled dryRun have you? Double check with:
[[GANTracker sharedTracker] setDryRun:NO];
Also try dispatchSynchronous, it'll block as it's sending but might help with if things aren't on the same threads:
[[GANTracker sharedTracker] dispatchSynchronous];
Just've checked it from scratch, dispatch perfectly worked meaning
a) your device is somehow different (i still have unsolved crashes on the particular iPad's 3 from Apple tester's unresolved, so it wouldn't be a huge surprise)
b) your code is somehow different - and that's much easier for you to fix.
For the a) there's no advice but to test it against all the devices you might get, for the b) i could only say what worked for me:
downloaded 1.4 SDK here
got Google sample projects with git clone https://code.google.com/p/google-mobile-dev.analytics-end-to-end/
configured final/AnalyticsSample to launch, changed the source slightly
(trackEvent::::: were called from sample, app was restarted manually as there's zero time period requiring dispatch call)
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[GANTracker sharedTracker] startTrackerWithAccountID:kGANAccountId
dispatchPeriod:0
delegate:self];
NSLog(#"Dispatch%#", [[GANTracker sharedTracker] dispatch] ? #"ed Successfully": #" Failed");
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
That's it, log says Dispatched Successfully, worth trying i guess.
cough
I'd misspelled the #define to start the tracker object in my app delegate. Other files were spelled correctly, hence the logging statements showing up, but when I tried to log just before the tracker was started it didn't show.
Oops. Well, at least there's a decent troubleshooting post for Google Analytics on SO now!
I'm creating an app which listens to significant location change events and in case the app gets terminated then the iOS launches the app with UIApplicationLaunchOptionsLocationKey set.
So, the documentation says to create a new location manager and register for location updates again. However, doesn't mention if I'm supposed to initialize my viewController (as I do in normal app launch as well)? My view controllers initialize in viewDidLoad but are created in appDidFinishLaunchingWithOptions.
Any idea how much time does OS provides to the App for location update handling? My app needs to make a webservice request if the location change indicates an interested location for the app.
Thanks
You should consider moving your initialization code to a new method, something like initializeViews. This method would check to make sure the views haven't been initialized and then initialize them. You would call this method from application:didFinishLaunchingWithOptions: and applicationWillEnterForeground:, but the call in application:didFinishLaunchingWithOptions: would only occur if the application wasn't going to the background.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
if([UIApplication sharedApplication].applicationState != UIApplicationStateBackground)
[self initializeViews];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self initializeViews];
}
- (void)initializeViews {
if(!viewsAreInitialized) {
...
viewsAreInitialized = YES;
}
}