I'm slowly working on my first simple timer app, which is starting to slowly come to life. At the moment I've done no saving of data for when my app enters the background, for the moment whilst writing my app it is always staying loaded during my testing, even if its in the background for a small time. All this is being done on the simulator.
My problem is that I have a Table View Controller with an NSInteger index property
#property NSInteger index;
that I use to manage the slow iteration step by step over an NSArray over time, by calling a doWork method.
Initial setup of my TVC and this property is performed as the view is prepared for segue from another view. More work is done on this property and other properties whenever my app receives local notifications or upon observing UIApplicationWillEnterForegroundNotifications.
All accessing of this property I've added debug logging around and I'm just confused with what I'm seeing
PrepareForSegue
# 19:38:29:058 - calls a method doWork which increments my property from -1 to 0, and sets a local notification. Logs show self=0x10bb661f0
I press the home button to put my app in the background for ~10 secs
The local notification fires and I tap the banner to bring my app back to the focus
My TVC's awakeFromNib function sets up a notification observer
as follows
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note) {
[self doWork];
}];
This notification fires twice! (for some reason?) each time causing my doWork method to be called
# 19:38:45:832 - doWork immediately shows my property is now back to -1 not the 0 it was set to before being backgrounded, it is incremented again to 0. Also it shows self as different at self=0x10974bbd0, a value it remains at now whilst the app is foregrounded.
# 19:38:45:836 - doWork is called again from this 2nd notification call, my property is correctly now still 0 from the last call, it is incremented again to 1.
after that my app delegate also gets it's didReceiveLocalNotification method called, which will also end up calling the same doWork method via another block in a Notification Center observer setup the same as the one detailed above.
# 19:38:45:857 - doWork is called and again the property has gone from the 1 that was set, back to 0... and is again incremented back to 1.
I just can't understand what's going on. Most of the properties in my TVC are still presumably fine as the rest of my logic showing the TVC contents continues to work fine. Why is my NSInteger getting mangled so?
I thought perhaps there could be some issues with threading and the local notification handling occurring perhaps simultaneously, I hoped that adding the mainQueue would help with this, I'd previously got this set to nil. Sadly it didn't make any difference.
I wonder why self changes after being backgrounded for only a short amount of time. Naively I presumed that as everything seemed to be working on coming back to the foreground (the view still displayed, with all its data seemingly intact aside from this NSInteger property) that the self ptr and object would be the same. It's not too much to imagine that perhaps its been relocated by the OS somehow, but still this shouldn't have caused the property to change.
I'm using cocoa lumberjack for logging, and I've turned off ASYNC logging as follows
#define LOG_ASYNC_ENABLED NO
Which should at least mean that log calls block till they've logged. I could appreciate that if i did have some threading issues perhaps the logging order would be slightly in doubt. But for the initial corruption of the property described above after the app enters the background there is ~10 seconds from when I write 0 to the property, and later read -1 back out of it. This is clearly not a threading timing issue at that point.
Why am I notified about entering the foreground twice? If my properties were left where I set them it wouldn't matter much, but still strikes me as a little odd.
Is there a problem with my using self within this block, I've seen that sometimes you may want to use a weak self pointers for these blocks, but I've seen examples where self is used directly as well.
Any help on understanding and hopefully fixing this would be really appreciated. I'm a little stuck and can't see what I've done wrong!
Cheers
So the answer to my problem as figured out by Woofbeans and Phillip Mills is that my awakeFromNib was being called each time i entered this TVC, and also I was failing to removeObserver on these notifications causing the stale undisplayed TVCs to stay around indefinitely. I'd not realised this key part of my repro of the problem.
Go into the TVC, come out, go back in and then you would have a duplicate of alerts in the app being caused by the fact that the original TVC was still around, being held onto by the strong reference to self within my own blocks.
I'm going to refactor this doWork functionality into my model so that it can persist and be handled better, independently of whatever view happens to be being displayed.
I also changed my block code to use a weakself pointer within the block, to hopefully stop that block from causing any object to persist purely because of the block being left behind.
Cheers everyone!
Related
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.
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 know it's sounds silly but just to clear a point.
Is there any chance that view did load will be called before didBecomeActive ?
Is it totally impossible ?
EDIT
We have a crash that happens when user is coming back to the app from the background and we start to use openGL. The crash error points that we try to use openGL in the background.
It is important to say that our app lives in the background as a VOIP app.
We try to figure out if there is a chance that somehow we are triggering something in the background thats causes the app restart openGl in the background.
In the stack we see:
[VideoCallViewController viewDidLoad] (VideoCallViewController.m:283)
And few lines after that:
[GPUImageContext createContext]
And finally:
gpus_ReturnNotPermittedKillClient + 10
We are trying to figure out if there is a way that [VideoCallViewController viewDidLoad] was called in the background or that we must assume that we are in the foreground, and somehow moving to the background right after the viewDidLoad ?
Second option
The second option is that we are indeed moving to the background right after the viewDidLoad. The point here is that we are listening to AppWillResignActive and we pause the GPUIMage. So we can not understand why do we get the crash ?
Thanks
Thanks
When / Where do you instantiate the various GPUImage objects that you are using? Is it within viewDidLoad or possibly within init:?
It's just pure rampant speculation here since you didn't really post any code...
but if you are disposing of objects when the app heads to the background that are not then re-created when it comes back to the foreground (perhaps because the viewController was retained by a parent, and therefore init: was not called again but viewDidLoad was...) Then you may be trying to send OpenGL messages to objects that don't actually exist anymore.
On the (probably unlikely) chance that my speculation is right, you could easily fix it with the common "getter" pattern of:
- (GPUImageObjectOfInterest*)instanceOfObject {
if (!_classVariableOfThisType) {
_classVariableOfThisType = [[GPUImageObjectOfInterest alloc] init];
// custom configuration, etc...
}
return _classVariableOfThisType;
}
and then use [self instanceOfObject]; wherever you used to use _classVariableOfThisType
It's a low overhead, but reasonably foolproof way of making sure a key object exists under a wide range of app interruption / background & foreground & low memory conditions.
Don't be shy to post too much code though, we can read through an entire class if needed. Some of us like reading code! (and it will really help the quality of response you get...)
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'm struggling with the following scenario and could use some different perspectives to shed some light on me:
I have a self.backstack which is an array of sections to go "back" to when you hit the back button. I'm getting an EXC_BAD_ACCESS when the back button is hit in a particular situation, but I'm not sure which object the code is mad about because everything seems there.
If you look on the bottom left of the image you'll see that self, backStack, and userInfo are all there. Not only that but their respective prints on are logged in the bottom right.
Any thoughts on what the problem might be? Thanks.
I suspect you have an observer of the notification which has been deallocated before it unregistered for the notifications.
Notifications are synchronous, which means that on the line you are crashing on, it is trying to run all of the observer callbacks. Check everywhere you are registering for these, and make sure the objects are either retained elsewhere, or are being properly unregistered (removeObserver iirc) when they are released.