[英]View controller responds to app delegate notifications in iOS 12 but not in iOS 13
我有一個支持iOS 12的應用程序。我正在添加對iOS 13的支持。我有一個視圖控制器,需要在應用程序進入后台時執行快速操作。
在iOS 13之前,這很簡單。 添加如下行:
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
在viewDidLoad
或init
。
然后添加didEnterBackground
方法:
@objc func didEnterBackground() {
// Do my background stuff
}
這對iOS 12及更早版本來說都很好。
但是現在iOS 13中的場景支持,當使用iOS 13運行時,我的通知沒有被調用。它仍然適用於iOS 12模擬器/設備。
我需要做出哪些改變?
在iOS 13下支持場景時,不再調用許多UIApplicationDelegate
生命周期方法。 現在UISceneDelegate
有相應的生命周期方法。 這意味着需要在iOS 13下監聽UIScene.didEnterBackgroundNotification
通知。您可以在管理應用程序生命周期頁面的文檔中找到更多詳細信息。
您需要將通知觀察者代碼更新為:
if #available(iOS 13.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIScene.didEnterBackgroundNotification, object: nil)
} else {
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
這允許您的視圖控制器(或視圖)根據其運行的iOS版本來監聽正確的事件。
根據iOS的版本,為兩個事件調用相同的didEnterBackground
方法。
但如果您的應用支持多個窗口,則會增加復雜性。
如果您的應用程序的用戶打開了應用程序的多個窗口,則即使給定的視圖控制器仍在前台或者已經在后台,此視圖控制器(或視圖)的每個副本都將收到后台事件的通知一直。
在可能的情況下,您只需要剛剛放入后台的一個窗口來響應事件,您需要添加額外的檢查。 通知的object
屬性將告訴您哪個特定場景剛剛進入后台。 因此代碼需要檢查通知的窗口場景是否與視圖控制器(或視圖)相關聯。
簡短的一趟 :有關如何獲取UIViewController或UIView的UIScene的詳細信息,請參閱此答案 。 (它並不像你希望的那樣簡單)。
這需要更新didEnterBackground
方法,如下所示:
@objc func didEnterBackground(_ notification: NSNotification) {
if #available(iOS 13.0, *) {
// This requires the extension found at: https://stackoverflow.com/a/56589151/1226963
if let winScene = notification.object as? UIWindowScene, winScene === self.scene {
return; // not my scene man, I'm outta here
} // else this is my scene, handle it
} // else iOS 12 and we need to handle the app going to the background
// Do my background stuff
}
有一種方法可以使這更簡單。 注冊NotificationCenter
,您可以將自己的窗口場景指定為object
參數的參數。 然后只為您自己的窗口場景調用didEnterBackground
方法。
這樣做的訣竅是在注冊通知時獲取自己的窗口場景。 由於只能在viewDidAppear
被調用至少一次后才能獲得視圖控制器的場景,因此不能使用任何init
, viewDidLoad
甚至viewWillAppear
。 這些都太早了。
由於viewDidAppear
可以被多次調用, addObserver
每次都會調用addObserver
,這是一個問題,因為那時你的處理程序將被多次調用一次。 因此,一種想法是在viewDidDisappear
取消注冊觀察者。 但是現在這有一個問題,即如果某個其他視圖控制器覆蓋它,則不會調用視圖控制器。 因此,它可以在viewDidAppear
添加觀察者,但只是第一次為視圖控制器的特定實例調用它。
如果你可以等到viewDidAppear
,那么首先你需要在你的類中添加一個屬性來跟蹤它是否被查看過。
var beenViewed = false
然后添加viewDidAppear
:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !beenViewed {
beenViewed = true
if #available(iOS 13.0, *) {
// Only be notified of my own window scene
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIScene.didEnterBackgroundNotification, object: self.view.window?.windowScene)
} else {
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
}
}
然后你的didEnterBackground
可以再次成為舊的簡單版本:
@objc func didEnterBackground() {
// Do my background stuff
}
對於Objective-C,代碼如下:
在viewDidAppear
之前注冊通知:
if (@available(iOS 13.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UISceneDidEnterBackgroundNotification object:nil];
} else {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
更復雜的didEnterBackground
:
- (void)didEnterBackground:(NSNotification *)notification {
if (@available(iOS 13.0, *)) {
// This requires the extension found at: https://stackoverflow.com/a/56589151/1226963
if (notification.object != self.scene) {
return; // not my scene
} // else my own scene
} // else iOS 12
// Do stuff
}
如果你想使用viewDidAppear
並有一個更簡單的didEnterBackground
:
將實例變量添加到您的類:
BOOL beenViewed;
然后添加viewDidAppear
:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!beenViewed) {
beenViewed = YES;
if (@available(iOS 13.0, *)) {
// Only be notified of my own window scene
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UISceneDidEnterBackgroundNotification object:self.view.window.windowScene];
} else {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
}
}
更簡單的didEnterBackground
:
- (void)didEnterBackground {
// Do stuff
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.