7

I am looking for a way to grab the current view being shown to the user when they send the application to the background.

The situation is that I have provided options in my settings bundle for look and feel that I would like to take effect when the applicationWillEnterForeground is fired.

Anyone have a suggestion as to how to attack this problem?

I tried to register a NSNotification, but it fires to late and the view appears to the user before the NSNotification method runs.

bdparrish
  • 3,216
  • 3
  • 37
  • 58
  • Is this two questions? 1.) How can I get the current view and store it when application is backgrounded (resigns), and 2.) How can I update said view before it displays when user restores app from background? – Sam Sep 30 '11 at 15:53
  • Have you tried calling `[view setNeedsDisplay]` or `[view setNeedsLayout]` to get the view to refresh (thus avoiding switching to a different view and back again to get the desired effect)? – Sam Sep 30 '11 at 16:40
  • @Sam, yes, I tried both of those methods. The View is still loaded so the UIView already shows before those calls fire the needed changes. – bdparrish Sep 30 '11 at 17:39
  • Have you considered changing the view during `applicationDidEnterBackground`? Then you don't need to worry about showing it in `applicationWillEnterForeground`. This appears to work for me. What exactly are you doing? Changing images, adding subviews, applying transformations? I'd like to try to replicate the bad behavior you're seeing. – Sam Sep 30 '11 at 18:10
  • @Sam, the issue is that, they can exit the application to change the application settings, and come back in to application. I want those settings applied if they changed them as soon as they come back into the application. – bdparrish Sep 30 '11 at 18:46
  • Ah, I feel dumb, should've realized that. Your question mentions the settings bundle and what you are after. I'll try something like that in a sample project. Also, if you ever decide you want settings in your app take a look at [In App Settings Kit](http://www.inappsettingskit.com/). – Sam Sep 30 '11 at 19:23
  • I just filed this bug with apple: [Can't Update UI when App Returns from Background](https://bugreport.apple.com/cgi-bin/WebObjects/RadarWeb.woa/5/wo/3oZ6Z2gT1hIK2kHEXQ1zO0/8.66). Did you ever find anything that worked for you? – Sam Nov 03 '11 at 15:16

4 Answers4

7

To grab the current view being shown when the user backgrounds your app, use your AppDelegate's applicationDidEnterBackground method.

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Get current view...  
    // (get from UITabbarController or whatever logic you like)

    // For this code sample, just grab first UIView under the main window
    UIView *myView = [self.window.subviews objectAtIndex:0];
}

To change the view before it shows, use the AppDelegate's applicationWillEnterForeground method like this:

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 80, 80)];
    label.backgroundColor = [UIColor whiteColor];
    label.text = @"yo";

    [self.myLastView addSubview:label];
}

I realize you mentioned the applicationWillEnterForeground in your question. Can you be more specific with what you are trying to do or possibly include code? I actually tried the code above and the view update (I see the label "yo" above my view).

My last suggestion is to try calling [view setNeedsDisplay] and [view setNeedsLayout] which should force the UIView to redraw itself. (note - issue isn't that uiview changes don't show up, issue is that they show up after the old view is shown. It appears a screenshot is taken before suspending app and this screenshot is initially shown upon resuming app for performance)

Edit

Code above is a good example of what user is seeing. The label "yo" shows up, but only after the view is restored. I'll see if I can fix this and repost.

Edit 2

It appears that resuming a suspended app shows a captured screenshot of the app's last known state as far as I can tell. I've tried to find docs to this effect, but I can't find it.

Alternative Solution 1

Have your app exit when the user hits the home button.

If you save the state of your app in either applicationWillResignActive: or applicationWillTerminate:, you can simply restore that state (navigate to correct tab user was last on) and in appDidFinishLaunchingWithOptions: you can update the UI before the user sees it. To have your app exit when backgrounded (suspended) put the key "Application does not run in background" - raw key: UIApplicationExitsOnSuspend to YES.

Doing this will guarantee that the user will see your app the way they configured it in settings without seeing a flicker of what it used to look like. I'm sorry I couldn't find a better way to do this. :(

Alternative Solution 2

Display your settings inside your app.

This obviously would require a design change, however more and more apps are showing settings inside the app. A popular third party library is In App Settings Kit. This lets you configure settings via a bundle / plist file just like you would for global app settings. It also looks and behaves just like the global settings. This will give you FULL control of any behavior you want inside your app.

Sam
  • 26,946
  • 12
  • 75
  • 101
  • I realize this may not fully answer your question, but I think this should help get a better discussion going. What specifically do you still need help with? What is / isn't working? I don't know if you've tried a simple example like the code I have above, which I've seen work, and are now tackling something more complicated which for one reason or another does not work. I'd like to help you work through it though if I have enough detail to look at. – Sam Sep 30 '11 at 17:06
  • 1
    so the more detail, is that the root controller is a UITabViewController, and then each tab is a NavController or UIView. I want to be able to capture the current UIView in the current selected tab. The settings will change if another tab is selected and then they come back to the original tab. I have yet to try your example, but maybe your answer will change with the new information. – bdparrish Sep 30 '11 at 18:49
  • Let me know if either of the alternative solutions will work for you. Unfortunately, it looks like there is no way to update the view before it is shown when resuming an app. – Sam Oct 03 '11 at 16:09
  • 1
    If terminating is not desirable, would it be possible to show a blank screen in `applicationWillResignActive:` so that the OS has this as it's "last state" screenshot? Might look at bit jarring when you re-enter the app but probably less so than the layout suddenly switching due to a preferences change. – jrturton Oct 03 '11 at 16:15
  • @jrturton Yes you can do that. I tried making a UI change in `applicationDidEnterBackground:` and I saw it immediately when the app was resumed. So, yes that would definitely work. – Sam Oct 03 '11 at 16:35
  • @jrturton Looks like someone offered a similar solution with the question: [Alter view before applicationWillEnterForeground](http://stackoverflow.com/q/6103616/590956). – Sam Oct 06 '11 at 20:58
0

Just in case someone comes around with the same problem:
It seems that Apple has implemented a new property in iOS7 on UIApplication which prevents using the previously taken snapshot when reentering into foreground - ignoreSnapshotOnNextApplicationLaunch

DAXaholic
  • 33,312
  • 6
  • 76
  • 74
0

I'm going to guess that you have it backwards.

The system may take a snapshot of the current screen, and it shows this when your app is restored to the foreground. It may be that this snapshot is showing the old look, before you get a chance to change it at applicationWillEnterForeground: time.

So, change when you get applicationWillEnterForeground:, then the snapshot will be taken from what you want to restore to.

David Dunham
  • 8,139
  • 3
  • 28
  • 41
0

In each viewDidLoad you can always post a notification, see NSNotification Class Reference, you can either store a reference to the view in NSUserDefaults, then do what you need to do when the user returns in applicationWillEnterForeground:

WrightsCS
  • 50,551
  • 22
  • 134
  • 186