rma*_*ddy 3 application-lifecycle ios ios13
我有一个支持iOS 12的应用程序。我正在添加对iOS 13的支持。我有一个视图控制器,当该应用程序进入后台时,它需要执行快速操作。
在iOS 13之前,这非常简单。添加一行,例如:
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
Run Code Online (Sandbox Code Playgroud)
在viewDidLoad
或也许init
。
然后添加didEnterBackground
方法:
@objc func didEnterBackground() {
// Do my background stuff
}
Run Code Online (Sandbox Code Playgroud)
对于iOS 12及更低版本,这一切都很好。
但是现在有了iOS 13的场景支持,在iOS 13上运行时不会调用我的通知。它仍然可以在iOS 12模拟器/设备上使用。
我需要进行哪些更改?
在iOS 13下支持场景时,UIApplicationDelegate
不再调用许多生命周期方法。现在有相应的生命周期方法UISceneDelegate
。这意味着需要UIScene.didEnterBackgroundNotification
在iOS 13下收听通知。您可以在“ 管理应用程序的生命周期”页面上的文档中找到更多详细信息。
您需要将通知观察者代码更新为:
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)
}
Run Code Online (Sandbox Code Playgroud)
这允许您的视图控制器(或视图)侦听正确的事件,具体取决于它运行在哪个iOS版本上。
didEnterBackground
根据iOS的版本,两个事件都调用相同的方法。
但是,如果您的应用程序支持多个窗口,则会增加复杂性。
如果您的应用程序用户打开了您的应用程序的多个窗口,则即使给定的视图控制器仍在前台或在后台,该视图控制器(或视图)的每个副本也会收到后台事件通知。一直。
在可能的情况下,您只希望仅将一个置于后台的窗口来响应事件,则需要添加额外的检查。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
}
Run Code Online (Sandbox Code Playgroud)
有一种方法可以使此过程更简单。使用进行注册时NotificationCenter
,您可以指定自己的窗口场景作为该参数的object
参数。然后didEnterBackground
将仅针对您自己的窗口场景调用该方法。
诀窍在于在注册通知时获得自己的窗口场景。由于您只能viewDidAppear
在至少调用一次之后才能获得视图控制器的场景,因此不能使用任何init
,viewDidLoad
甚至viewWillAppear
。这些还为时过早。
由于viewDidAppear
可以被多次调用,因此您addObserver
每次都会结束调用,这是一个问题,因为这样您的处理程序将为单个事件多次调用。因此,有一种想法是注销的观察者viewDidDisappear
。但是,这现在有一个问题,如果某个其他视图控制器正在覆盖它,则不会调用您的视图控制器。因此,技巧是viewDidAppear
在第一次为视图控制器的特定实例调用时添加观察者。
如果您可以等到viewDidAppear
,则首先需要在类中添加一个属性,以跟踪是否已查看该属性。
var beenViewed = false
Run Code Online (Sandbox Code Playgroud)
然后添加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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后您didEnterBackground
可以再次成为旧的简单版本:
@objc func didEnterBackground() {
// Do my background stuff
}
Run Code Online (Sandbox Code Playgroud)
对于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];
}
Run Code Online (Sandbox Code Playgroud)
更复杂的didEnterBackground
:
- (void)didEnterBackground:(NSNotification *)notification {
if (@available(iOS 13.0, *)) {
// This requires the extension found at: /sf/answers/3961240601/
if (notification.object != self.scene) {
return; // not my scene
} // else my own scene
} // else iOS 12
// Do stuff
}
Run Code Online (Sandbox Code Playgroud)
如果您想使用viewDidAppear
并且更简单didEnterBackground
:
将一个实例变量添加到您的类中:
BOOL beenViewed;
Run Code Online (Sandbox Code Playgroud)
然后添加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];
}
}
}
Run Code Online (Sandbox Code Playgroud)
而且更简单didEnterBackground
:
- (void)didEnterBackground {
// Do stuff
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
975 次 |
最近记录: |