Wie kann ich am besten erkennen, wenn die App für meine Ansicht in den Hintergrund tritt?

77

Ich habe einen Ansichts-Controller, der einen verwendet NSTimer, um Code auszuführen.

Was ist der beste Weg, um zu erkennen, wann die App in den Hintergrund tritt, damit ich den Timer anhalten kann?

jfisk
quelle

Antworten:

171

Sie können jede Klasse, die interessiert ist, wenn die App in den Hintergrund tritt, Benachrichtigungen erhalten. Dies ist eine gute Alternative zum Koppeln dieser Klassen mit dem AppDelegate.

Bei der Initialisierung dieser Klassen:

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

Antworten auf die Benachrichtigungen

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

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

}
Jesse Black
quelle
2
Ich hatte ein kleines Update für diesen Code zur Arbeit zu machen: durch einen Doppelpunkt zu den Methodennamen innerhalb der Zugabe @selector, dh Ersetzen @selector(appWillResignActive)mit @selector(appWillResignActive:)(und gleiche gilt für @selector(appWillTerminate:)).
Piovezan
@Piovezan, der Grund, warum Sie das ":" benötigen, ist, dass, wie auch immer Sie Ihre Methode nennen, immer noch "..ein und nur ein Argument (eine Instanz von NSNotification)" verwendet werden muss. - Klicken Sie bei gedrückter Alt-Taste mit der linken Maustaste auf die addObserver-Deklaration, um mehr zu erfahren.
Serge-k
Gute Antwort! Danke, dass du mir das Ziehen von Haaren erspart hast !!
Septronic
willResignActive bedeutet nicht, dass es in den Hintergrund tritt - es bedeutet, dass es inaktiv wird. Ein eingehender Anruf über Ihrer App macht Sie beispielsweise inaktiv, ebenso wie das Popup-Dialogfeld auf Systemebene. UIApplicationDidEnterBackground ist die Benachrichtigung, um tatsächlich in den Hintergrund zu treten.
Chadbag
25

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) {

}
Ashok R.
quelle
1
Wo heben Sie die Benachrichtigung hier ab?
Thexande
1
@ Thexande, wenn ich richtig bin Swift 4 erledigt das für Sie und Sie müssen die Benachrichtigung nicht mehr abmelden (es sei denn, Sie können nicht warten ;-)
Stephane Paquet
2
@StephanePaquet aus Apples Dokumenten: "Wenn Ihre App auf iOS 9.0 und höher oder auf macOS 10.11 und höher abzielt, müssen Sie die Registrierung eines Beobachters in seiner Dealloc-Methode nicht aufheben." :)
Rob VS
10

In Ihren Anwendungen AppDelegate wird die (void)applicationDidEnterBackground:(UIApplication *)applicationMethode von iOS aufgerufen. Sie können Ihren Timer dort anhalten.

Damien
quelle
2
Ihre App kann sich auch für UIApplicationDidEnterBackgroundNotification-Benachrichtigungen registrieren.
Marco
8

Für diejenigen, die dies in Swift tun möchten:

Am init:

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

Am deinit:

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

Antwort auf die Benachrichtigung:

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

Apple empfiehlt uns, dynamische Versand- und Objective-C-Selektoren in Swift nach Möglichkeit zu vermeiden. Dies ist jedoch immer noch der bequemste Weg, dies zu tun.

Luke
quelle
2

In schnellem 4.1:

Ich benutze die Verschlussversion:

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)
}

Die addObserverMethode gibt ein undurchsichtiges Objekt zurück, das irgendwann entfernt werden muss.

Juanjo
quelle
1

Nur eine Randnotiz: Wenn Sie einen Controller A registrieren, um im Hintergrund benachrichtigt zu werden, achten Sie darauf, dass er auch dann aufgerufen wird, wenn Sie (z. B.) einen zweiten Controller B drücken und B anzeigen: Wenn dieses Verhalten nicht korrekt ist ist besser zu registrieren / abmelden in

didAppear / WillDisappear.

ingconti
quelle
0

- (void)applicationWillResignActive:(UIApplication *)applicationauf Ihrem App-Delegaten. Sie können sich auch für die UIApplicationWillResignActiveNotificationBenachrichtigung für andere Objekte registrieren .

Sie müssen den Timer jedoch nicht unbedingt anhalten. Wenn Sie nichts tun, wird die App trotzdem in den Ruhezustand versetzt und führt keinen Code aus. Vermutlich wird Ihr Timer ausgelöst, wenn Sie wieder aktiv werden (falls Sie dies tun). Wenn Sie etwas Besonderes tun müssen, gibt es Delegierungsmethoden und Benachrichtigungen, für die Sie sich ebenfalls registrieren können.

smparkes
quelle
Wie bereits erwähnt, gibt es eine "Hintergrund" -Version, die dem aktiven Rücktritt ziemlich ähnlich ist, wenn Sie nur auf 4.0 und höher abzielen. Die "aktiven" Versionen gehen auf 2.0 zurück.
smparkes
+1, wusste nicht, dass Sie den Benachrichtigungsteil hatten, als ich meine Antwort aufstellte
Jesse Black
1
Genau genommen wird eine App, die den aktiven Status zurücktritt, möglicherweise nicht im Hintergrundstatus angezeigt (z. B. bei einer vorübergehenden Unterbrechung wie einem Telefonanruf oder einer SMS).
Marco
1
@marco: vereinbart. Ich war ein bisschen schnell und locker. Viele Leute (können sich über das OP nicht sicher sein) unterscheiden nicht wirklich zwischen inaktiv und Hintergrund. Angesichts der Art und Weise, wie die Frage formuliert wurde, dachte ich, dass Inaktivität mehr das war, wonach er suchte, aber vielleicht bin ich zu weit gegangen. FWIW, bestimmte modale Popups vom Betriebssystem (z. B. für Netzwerk- und Standortanforderungen) lösen ebenfalls einen aktiven Rücktritt aus.
smparkes
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
}
thexande
quelle
0

Dies ist eine bessere Lösung mit Verschluss

Beobachter erklären

var backgroundObserver: NSObjectProtocol?

Initialisieren Sie den Beobachter 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  
}

Vergessen Sie nicht, den Beobachter in deinit zu entfernen

deinit {
    if let observer = backgroundObserver {
        NotificationCenter.default.removeObserver(observer)
    } 
}
Mohammad Sadiq
quelle