I've come across a strange error while programming my iPhone application. Basically when I leave my application in the background and then access it after a long time (i.e. the entire night while I'm sleeping), the viewDidLoad method seems to be called again even though I did not exit the app (I only double tapped the Home button or I tapped the Home button once) but still left the app in the background. However, if I leave the app on for a short period of time (anytime between a few minutes to a few hours), the viewDidLoad method is not called again and everything is as it should be. After doing some research, I found that it is because the viewDidUnload method is called (after the OS finds that the app is suspended for a long time), which calls viewDidLoad again when we bring the app back up. I found this out through this link: view seems to reload itself but it doesn't seem that there's a way to prevent viewDidLoad from being called when the viewDidUnload is called. Is there any way to prevent this viewDidUnload method from being called again? The thing is I want my app to be running for a long time in the background (i.e. a few days in the background) to collect data. Or, is there no way around this? Any help would be appreciated. Thanks!
EDIT: I have realized that after iOS 5, viewDidUnload is deprecated but this phenomenon still occurs. Any ideas on how to fix it? Thanks!
If you want to do stuff in the background you should look into background tasks.
Related
I have a Swift iOS app consisting of 3 view controllers – the initial one with a tableview, the second one with the chosen element and ability to create a new time session and the third one with the actual timer for the session (let’s call it the timer vc).
In this case, the focus is the timer view controller. However, the question is not about the timer itself. It works both in foreground and background mode. The problem is this:
The app goes background. Then over a certain fixed period of time, it receives a local notification – a reminder to go back to the timer vc and save the results. Most of the time, it works fine but sometimes when you go back to the app (through notification), it opens the initial vc with the tableview instead of the timer vc, which seems like the system terminates the background app after a while and then reopens it when you go back through the notification. In this case, all the data from the timer vc are obviously lost since the app logic requires that the user save the data after the session is finished.
What I think, the essence of the problem may have to do with how long the app can stay in the background without being terminated or suspended (If I’m not mistaken, in this state, all the current data associated with the app are removed from the memory). I mean, when you set the notifications to be triggered like every 1, 5 or 10 minutes, everything seems to be fine. However, when the notification is set for 30 minutes or more, the mentioned bug seems to appear from time to time (especially when testing on an actual device instead of a simulator). For the most part, it appears if the device storage is almost full - under 1Gb of free space). Which leads me to believe that this may also be a memory management issue.
How to make this timer vc run in the background as much time as needed? Also, does anybody know how much time an iOS app is guaranteed to stay in the background without being removed from the memory? Thanks a lot.
There is no guarantee of your's app execution time when it is in background mode. The operating system can suspend it anytime, Operating system has the responsibility only to notify your app which you will receive in the app delegate.
For setting up the local notification, you need to get the help from OS only. You can't rely on your app's execution in the background thread. For scheduling and handling of local notifications, you can go through the following documentation.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SchedulingandHandlingLocalNotifications.html#//apple_ref/doc/uid/TP40008194-CH5-SW1
First of all Check This to understand what i am doing
I did not get my answer in above question & still waiting for it.
Now new porblem is that when i click on back button using following code, methods of last ViewController are still running. It will use memory & keep processing untill it gets response(that`s what i want to do but if user press back then i want to stop all methods)
[self.navigationController popViewControllerAnimated:YES];
How do i stop it?
You need to do [getTryAgainTask cancel] (assuming getTryAgainTask is of type NSURLSessionDownloadTask) before you pop this controller. The download task is asynchronous and runs irrespective of the controller (that fired it) being deallocated. This might cause retain loops, leading the app to eventually crash. The code as of now, will go into an infinite loop. A better solution would be to keep a tab on the number of retries (say 3 times) and then prompt the user about the problem, asking if he/she would like to try again.
I'm having an issue where my app is crashing on sleep, and sometimes on home. I'm getting a BAD_ACCESS error in a thread called gpus_ReturnNotPermittedKillClient, which tells me that my app is making UI changes in the background, which to my understanding is a no-go. Therefore, I'm stepping through my code to see what happens on home / sleep, and I find that my breakpoint in my VC's -viewWillLayoutSubviews method is getting hit AFTER the breakpoints in the -applicationWillResignActive and -appplicationDidEnterBackground notifications (in which I'm attempting to stop all updates from an asynchronous callback function).
That doesn't seem to make any sense. From the application's perspective, if it's not cool to do UI updates in the background, why call viewWillLayoutSubviews after you're in the background?
EDIT: It appears to do this even when my app doesn't crash. Could it just be lldb getting things out of order?
I think you simply need to be tolerant of this. Per this tech note, you can't do any GLES rendering in the background. My recommendation would be for your app to set a flag when applicationWillResignActive is called, and then before doing any rendering work you check that flag and don't do the work (and perhaps just call -setNeedsDisplay on the view so that if your app becomes active again it will know to draw that view). You seem troubled by the fact that viewWillLayoutSubviews is getting called "late", but I don't see how that really matters. (i.e. layout != rendering) I would be surprised if your view's -drawRect: method were getting called after applicationDidEnterBackground but I would still say that it would be your responsibility to check a flag and not render if your app is in the background.
I have a timer in my app, and I want it to appear to be running while my app is on the background. I'd like that if the user presses the home button when the timer shows, for instant "01:11:11" and then goes back to the app and it becomes visible to him 10 minutes later, to see the timer as "01:01:11", however I get a split second where it shows the last state when the app went to the background ("01:11:11") before it starts updating from the correct time.
I assumed that I could correct this by updating the state of my timer in "applicationDidBecomeActive" and it did work on my simulator in Xcode but not on my Ipad.
I'm using cocos2d for my drawing and this is what I'm doing in my applicationDidBecomeActive:
CCScene *s=[director_ runningScene];
GameLayer *l=[(GameLayer*)[s getChildByTag:GAME_LAYER_TAG];
if (l!=nil) [l myUpdate];
I don't think it's relevant to the problem though because myUpdate does get called but I still have that split second glitch on my Ipad, as if it starts back from its last state no matter what.
In apples clock app, in applicationDidEnterBackground it hides the timer text, so that when the app comes into the foreground you see a blank UI for the split second where your app is loading the new timer data in the UI. Also, you may want to call some of your applicationDidBecomeActive code in applicationWillEnterForeground, which is called first. But keep in mind, applicationWillEnterForeground is not called when the app first launches.
There will always be a delay between when your app comes into the foreground, and when the UI updates. Theres no way to fix that, so you might as well use what apple uses to get around the issue.
Well I tried to hide my UI in both applicationWillResignActive and applicationDidEnterBackground. Since applicationWillResignActive is called first and before going into preview (double click on HOME) it causes a "not so pretty" preview but I thought at least it would solve my original problem. It didn't (not, on my IPad). It looks like the system takes the screen shot even before applicationWillResignActive.
I checked the timer in the official clock app and I see the clock is updating even when the app is in the background (in preview), so they "cheat" anyway...
I am developing an application for the iphone that, in viewDidLoad, calls arc4random to get a random number. My problem is that each time the application starts, it gets the same number from arc4random. I ought to point out that I see this behaviour when I test the app on my iphone device and start the application from the device touchscreen. If I run the app on the device from xcode, then I see different random numbers.
Any help or advice would be appreciated. Thanks.
arc4random does not need seeding and should not be returning the same results each time you call it.
From your comments, it seems to me that your code is not being executed each time your app comes to the foreground. Remember that when you press the home button your app is not terminated by default. It will enter the background, and will resume when you tap the icon again.
If your code is inside viewDidLoad, it will only be called once which means your variable will not be updated and will contain the same value each time you inspect it. When you run from Xcode your app will be fully terminated each time and you will get the expected behaviour.
You should probably put your code in viewWillAppear: or viewDidAppear: so it is called whenever the view appears on screen, rather than once when your view initially loads.