I have encountered a problem in my app that didFinishLaunchingWithOptions was taking too long to finish, what could possibly result in the app being terminated.
I have also been getting crash reports from itunes connect that seem to indicate that the app takes too long to launch.
This might be caused by the fact that I was loading some textures synchronously during didFinishLaunchingWithOptions, a process that takes more than a second.
In an attempt to solve it, I call the method that loads the data after delay, in the following way:
[self performSelector:#selector(loadTextures) withObject:nil afterDelay:0.5f];
The way I understand - though I might be wrong - the scheduled task will not be carried out on a different thread, and therefore will only be processed after didFinishLaunchingWithOptions is done.
My question is:
Are there any best practice solutions for such a problem? Is the solution I suggested works as I intended?
Also, is apple's watchdog known to check apps for responsiveness even after the launch phase in cases such as this?
We had a similar problem in our ebook reader application where we copy ebooks (of several MBs) from bundle to the documents directory.Scheduling selector for copying the books has been the best solution so far.The same solution works fine in your case as well.I am not sure about apple's watch dog but our application is live on the app store and running since more then one year with this solution incorporated.
Related
So I have an app that has twice been rejected from the app store and I really could use some help!
It has been rejected for the Watchdog timer forcing it to quit when it is first opened. However I have not been able to reproduce this on any of my devices. It does take a long time to build to a device when using xcode (i know that when built from xcode the watchdog is disconnected). But I have a couple questions that might help me fix this.
Does the watchdog take into account only didFinishLaunchingWithOptions: or are their other methods that it calls?
Does the number of frameworks used by the program have anything to do with it? and if so is 11 frameworks just too many?
Once the app is installed to a device, and I unplug said device is the watchdog timer re-enabled?
What are some other things that can add to the watchdog timer?
Apple said that another possibility could be Another possibility could be a missing entitlement. Could someone please explain what this means, I hav'nt seen this before with my other apps but thought maybe it was something new? And does it have to be installed on all apps for the appstore?
Time Profile for first seconds
You are blocking the UI thread for too long. To solve this problem, first you'll need to figure out what code took that long. It might be worthwhile to profile your app. Note that the simulator doesn't emulate the device, it only emulates the API. It could run much faster than the actual device because your computer is more powerful than an iPhone. Try click and hold Run at top left of Xcode, and choose Profile. Choose Time Profiler and run for a few seconds. Stop the profiler to analyze timing in function calls. Note that you may need to dig deeper, find some tutorials or books to really understand profiling.
When you know what parts have been running slow. You can put them into a thread. The easy way would be to use Grand Central Dispatch. To get started, visit this tutorial. You can skip the first half and focus on the actual thread blocks. The APIs are dispatch_queue_create, dispatch_async and dispatch_release.
This will unblock your UI.
Do you do a lot of processing in
application:didFinishLaunchingWithOptions,
applicationDidBecomeActive,
applicationDidEnterBackground,
applicationWillResignActive or
applicationWillTerminate?
Things like multiple file access, loading/saving data, synchronous network access can cause your application to freeze on startup or when the user exits, and could cause the watchdog to kill your app.
This Apple Technical note suggests that the watchdog is only looking at the launch, suspend, resume and terminate user interface events, so I would say you should look into these first, and maybe post back some more details of what your app does in the methods listed above.
http://developer.apple.com/library/ios/#qa/qa1693/_index.html
11 frameworks is fine. I have used 11 in an app no problem.
If you start the app up by tapping the icon on the home screen then the watchdog timers will be active and monitoring your app. If you start the app up by hitting run or debug in Xcode, then the watchdog will not be monitoring your app.
I have a weird situation, client does't want their application to support multitasking so I created a flag in info.plist like,
Application does not run in background = YES;
However there are times during application lifecycle that the application must upload some data to server before it terminates. If it doesn't then server will have fuzzy data and my client's company (and probably me too...) will be doomed!!!
Now my questions are,
How much time do I have before OS will terminate my app? Sometimes data can be large to upload and if internet is slow then I might need more time.
I saw this method beginBackgroundTaskWithExpirationHandler will this work in my situation. I doubt as this might work if I do support background execution. am I right?
Final questions,
Any other options I can think of?
should I resign as a iOS developer?
Thanks
My advice would be to try something like this:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(saveWhatever)
name:UIApplicationWillTerminateNotification
object:nil];
Just put that code in the init method of your class. Be sure to remove yourself as an observer in viewDidUnload like this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Here you can save whatever you need to save, but I'm not sure about uploading data. Your best bet is to save the data to a file here, and then next time the app is opened upload the data from the file to the server asynchronously. You can try uploading it with this notification, I'm just not sure Springboard is going to wait around for that to happen.
Resign? probably not, but look for work in another company with realistic expectations? definitely. It's been my experience that clients who insist on rediculous design ideas and won't listen to reason are more likely to blame the developer when it all goes pear shape.
As for trying to upload data when terminating. Don't do it. The watch dog timer is not predictable in how much time your app will get before the timer assumes it is hung and kills it. I hit a similar situation recently when I started working on a established project where the app was randomly failing to start. The problem was that the developers had put download code into the application:didFinishLaunchingWithOptions: method. Because of internet latency and server latency issues, the method was taking too long and should have had it's code moved to a background thread.
Trying to do the same thing on termination, sleep, etc will have the same problem and there is no known way to stop the watchdog timer from killing your app.
The other question I have is why is the client resistant to multitasking? why do they care? They actually cannot stop it anyway because it's effectively part of any app. I presume that if they don't want multitasking they also don't want any form of internet access or animations. Because without threading those things, your UI is very likely to be unuseable, earning you a lot of 1 star ratings and complaints.
Does it matter when you upload the data to the server? Does it have to be right before application terminates?
If not, then I have this suggestion:
In the App Delegate method applicationWillTerminate, write all your data into a text file, something like mydata.txt, of your application sandbox filesystem (namely in the Library/Cache directory. Can't use the Document directory for app generated files. Apple now uses Document directory for iCloud syncing so putting your files there will result in app being rejected). Also need to mark your file with don't sync to iCloud attribute.
Then on the next launch of your application, you can check for the existence of this "mydata.txt" file. If it exists, read all the data from it and upload to your server. Then delete the file from the Library/Cache folder so next time it doesn't upload the same data. You can do this in the App Delegate's applicationDidFinishLaunching method.
Tearing my hair out on this, any thoughts or suggestions would be greatly appreciated.
I have an object that calls performSelectorOnMainThread:withObject:waitUntilDone: on itself from a child thread. This works fine 95% of the time. Every once in a while since iOS betas and now into release, a device will refuse to execute the performSelectorOnMainThread:withObject:waitUntilDone: calls... No error message, it doesn't crash, I can't make a device go into a state where it "fails" but once it's there it continues to fail until I either delete and re-install the app, or force it to quit, then adjust it's location services allowance, then launch it again, then re-adjust it's location services again back to normal... restarting the device does not fix it. Re-installing without deleting first doesn't fix it. It's very strange.... I know it works most of the time because most devices have no problems, however some devices fail somewhat regularly (every 3 or 4 days maybe). I know it's specifically that performSelectorOnMainThread:withObject:waitUntilDone: is not calling what it should because I've got a failing device now, and I've put an NSLog into the method that should be called. It function fine, but on the failing device, when performSelectorOnMainThread:withObject:waitUntilDone: is used to call that method the NSLog shows it's not being run...
This started happening with iOS 5 betas and again, happens on release. It happens most often on 2 of my devices, but on none of the other 10 devices I have personally tested on. I assumed it was just my device from some hiccup in the beta, but it happens on my brand new 4S which never touched beta, as well as on one user's iPad 2 (not on my iPad 2).
I really don't know where to look. I tell it to execute and it usually does on almost every device, but the same line gets no response and no errors etc. on some...
performSelectorOnMainThread:withObject:waitUntilDone can be wonky sometimes. Have you thought about trying to use lib dispatch?
You can create a block and post it on the main thread like this:
dispatch_async(dispatch_get_main_queue(), ^{
<do work here>
});
This would have the same save affect as using performSelectorOnMainThread:withObject:waitUntilDone
http://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
A Thread's RunLoop has several different modes.
It is possible that during the time you make your call the main thread is running in a mode different than the default one (which is the one targeted by performSelectorOnMainThread:withObject:WaitUntilDone:.
Consider using performSelectorOnMainThread:withObject:waitUntilDone:modes:
See Apple's documentation.
Also - GCD (libdispatch) is awesome, but it won't protect you from cooking yourself a deadlock:
Consider the case where your method is running on the main thread and you're calling:
dispatch_sync(dispatch_get_main_queue(), ^{
<do work here>
});
guys :)
I have an iOS alarm app, which uses UILocalNotification-s to schedule the user defined alarms if the app enters background. Since this (in my implementation) can be a relatively long process, I need to make sure that the registering of the notifications is completed before the app goes inactive. I read that there is a method in UIApplication: beginBackgroundTaskWithExpirationHandler, which asks iOS for more time, so that it can complete its tasks, but I have no idea how to use it. These (void(^)(void)) parameters scare me :). I know it's too much to ask, but... if I have a method [self registerLocalNotifications], which registeres all local notifications, can you please point me how to make sure the method finishes before the app goes to background. Huge thanks!
This looks like good sample code where you can see the usage of blocks ^{} together with applicationDidEnterBackground: http://iphonesdkdev.blogspot.com/2010/04/local-push-notification-sample-code-os.html
My app main thread is displaying a movie at the beginning , while other thread are doing background tasks.
Some however, are using PerformSelectorInMainThread to do some stuff.
What happens is that sometimes the movie just get stuck indefinitely , sometimes not , and sometimes get free after a couple seconds.
I'm trying to debug it, however when I'm pausing XCode while the app is stuck all I see is assembly code and I can't really understand anything from it. (I guess something like "symbols" on windows would be cool)
Is there a way to analyze more thoroughly what is running on the main thread and might stuck my video while it's playing ?
Moreover, how come the video get stuck anyway, if i'm playing a video from the main thread while other thread calls PerformSelectorInMainThread , what is really happening (I assumed it would add the selector as an event but won't disturb the movie from playing till the end) ?
Thanks for your help!!
Have you tried using Shark (one of the Instruments tools) to analyze samples?
When things are getting "stuck", it likely means the CPU is churning. Shark samples the CPU every so often (well, in human terms, VERY frequently) during a short burst (I would keep it under 5-10 seconds) and tells you what percentage of the time the CPU is spending on what tasks.
It does exactly what you mention - reverse engineers all the assembly code to look more like the debugger (well, not 100%, but enough).
That would be the first step - identifying the processor-heavy task that your performSelectorOnMainThread: code is calling that causes the video to gum up. Then, once you know what it is - the answer will either be obvious - or you'll have to change your architecture :)