What's the best way to detect when the app is entering the background for my view?
Asked Answered
M

10

81

I have a view controller that uses an NSTimer to execute some code.

What's the best way to detect when the app is going to the background so I can pause the timer?

Melodic answered 25/1, 2012 at 23:16 Comment(0)
P
175

You can have any class interested in when the app goes into the background receive notifications. This is a good alternative to coupling these classes with the AppDelegate.

When initializing said classes:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];

Responding to the notifications

-(void)appWillResignActive:(NSNotification*)note
{

}
-(void)appWillTerminate:(NSNotification*)note
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];

}
Pepsinogen answered 26/1, 2012 at 1:4 Comment(3)
I had to make a small fix for this code to work: by adding a colon to the method names inside the @selector, i.e. replacing @selector(appWillResignActive) with @selector(appWillResignActive:)(and same for @selector(appWillTerminate:)).Cephalization
@Piovezan, the reason you need the ":" is because whatever you call your method it must still take "..one and only one argument (an instance of NSNotification)." - Just Alt + left click on the addObserver declaration to find out more.Deer
willResignActive does not mean it is going into the background -- it means it is going inactive. For example, an incoming call on top of your app will make you inactive as will system level dialog popup. UIApplicationDidEnterBackground is the notification for actually going into the background.Cup
C
26

In Swift 4.0

override func viewDidLoad() {
    super.viewDidLoad()

    let app = UIApplication.shared

    //Register for the applicationWillResignActive anywhere in your app.
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.applicationWillResignActive(notification:)), name: NSNotification.Name.UIApplicationWillResignActive, object: app)
}

@objc func applicationWillResignActive(notification: NSNotification) {

}
Cloison answered 29/10, 2016 at 7:21 Comment(3)
Where are you un-registering the notification here?Sharpset
@Sharpset if I'm correct Swift 4 does it for you and you do not have to un-register Notification anymore (unless you cannot wait ;-)Mammet
@StephanePaquet from Apple's docs: "If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method." : )Crossly
L
10

On your applications AppDelegate the (void)applicationDidEnterBackground:(UIApplication *)application method will be called by iOS. You can stop your timer in there.

Libation answered 25/1, 2012 at 23:19 Comment(1)
Your app can also register itself for UIApplicationDidEnterBackgroundNotification notifications.Vanderpool
H
8

For those looking to do this in Swift:

On init:

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplicationWillResignActiveNotification, object: nil)

On deinit:

NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationWillResignActiveNotification, object: nil)

Responding to the notification:

dynamic private func applicationWillResignActive() {
    // Do things here
}

Apple encourages us to avoid dynamic dispatch and Objective-C selectors whenever possible in Swift, but this is still the most convenient way to do this.

Hogback answered 7/7, 2016 at 15:3 Comment(0)
P
2

In swift 4.1:

I use the closure version:

var observer: NSObjectProtocol!

// inside init or viewDidLoad:
observer = NotificationCenter.default.addObserver(forName: .UIApplicationWillResignActive, object: nil, queue: nil) { _ in
    print("willResignActive")
}

deinit {
    NotificationCenter.default.removeObserver(observer)
}

The addObserver method returns an opaque object that needs to be removed at some point.

Pullen answered 17/7, 2018 at 17:19 Comment(0)
Y
1

only a side note: If you register a controller A to be notified going background, be careful that it will be called even if you (for example..) push a second controller B and You are displaying B: If this behaviour is not correct, is better to register/unregister in

didAppear/WillDisappear.

Yogurt answered 8/4, 2018 at 7:12 Comment(0)
K
0

- (void)applicationWillResignActive:(UIApplication *)application on your app delegate. You can also register for the UIApplicationWillResignActiveNotification notification on other objects.

You don't necessarily need to pause the timer, though. If you don't do anything, the app will get put to sleep anyway and won't execute any code. Presumably your timer will fire when you become active again (if you do). If you need to do something special there are 'did become active' delegate methods and notifications you can register for as well.

Kittykitwe answered 25/1, 2012 at 23:19 Comment(4)
As mentioned, there is a "background" version that's pretty similar to resign active if you're only targeting 4.0 and later. The "active" versions go back to 2.0.Kittykitwe
+1, didn't realize you had the notification portion when I put up my answerPepsinogen
Strictly speaking an app resigning active state may not end up in background state (e.g. in the case of a temporary interruption such as a phone call or SMS).Vanderpool
@marco: agreed. I was being a little fast and loose. A lot of people (can't be sure about the OP) don't really differentiate between inactive and background. I thought, given the way the question was phrased, that inactive was more what he was looking for but maybe I went to far there. FWIW, certain modal pop ups from the OS (e.g., for network and location requirements) will also trigger resign active.Kittykitwe
S
0

Swift 4:

init() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(applicationWillResignActive),
                                           name: NSNotification.Name.UIApplicationWillResignActive,
                                           object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self,
                                              name: NSNotification.Name.UIApplicationWillResignActive,
                                              object: nil)
}

@objc private func applicationWillResignActive() {
    self.header.blur.effect = nil
}
Sharpset answered 25/6, 2018 at 19:46 Comment(0)
O
0

This is a better solution using closure

Declare observer

var backgroundObserver: NSObjectProtocol?

Initialize observer in viewDidLoad

backgroundObserver = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { [weak self] notification in
  // Do what you want to do when app would go to background/ resign active  
}

Don't forget to remove observer in deinit

deinit {
    if let observer = backgroundObserver {
        NotificationCenter.default.removeObserver(observer)
    } 
}
Oneself answered 9/11, 2020 at 11:49 Comment(0)
D
0

In Swift 5.1

    override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)

         NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
    
         NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
        }
    
    override func viewWillDisappear(_ animated: Bool) { 
        super.viewWillDisappear(animated)

        NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)

        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    }


@objc private func applicationWillResignActive() {
    }

    @objc private func applicationDidBecomeActive() {
    }
Delsiedelsman answered 1/2, 2021 at 5:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.