如何在 AppDelegate 和 ViewController 之间共享属性,并在 App 终止前保存
Posted
技术标签:
【中文标题】如何在 AppDelegate 和 ViewController 之间共享属性,并在 App 终止前保存【英文标题】:How to share properties between AppDelegate and ViewController, and save before App is terminated 【发布时间】:2019-05-12 03:29:35 【问题描述】:我有一个在 viewController 中更新了属性的类。我想在应用程序进入后台或使用 AppDelegate 退出时保存属性。我使用了以下代码,但似乎属性没有传递给 AppDelegate。此外,applicationWillTerminate 代码似乎没有被执行。
// testClass is defined and the properties are updated in viewController, e.g
testClass.status = true // default is false
// I want to save testClass.status when the app goes into background or being terminated using the following:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var vc = ViewController()
func applicationDidEnterBackground(_ application: UIApplication)
print(vc.testClass.status) // prints false
//codes to save
// save before App is terminated
func applicationWillTerminate(_ application: UIApplication)
print(vc.testClass.status) // this code did not get executed?
//codes to save
【问题讨论】:
【参考方案1】:applicationWillTerminate
仅在用户终止应用程序而不将其切换到后台模式时调用。
当应用程序处于活动状态时,双击主页按钮并终止应用程序。
但如果你将应用切换到后台,然后尝试终止应用,applicationWillTerminate
将不会被调用。
您正在AppDelegate
中创建ViewController
的实例
var vc = ViewController()
如果您更改另一个 ViewController
类实例中的 testClass 属性,您将不会在此处获得该值。所以像这样创建一个singleton
类
class TestClass: NSObject
static let shared = TestClass()
private override init()
super.init()
var status = false
现在从单例类更新任何视图控制器中的值
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
TestClass.shared.status = true
在AppDelegate
中保存并从UserDefaults
检索值
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
TestClass.shared.status = UserDefaults.standard.bool(forKey: "Status")
return true
func applicationDidEnterBackground(_ application: UIApplication)
UserDefaults.standard.set(TestClass.shared.status, forKey: "Status")
func applicationWillTerminate(_ application: UIApplication)
UserDefaults.standard.set(TestClass.shared.status, forKey: "Status")
或者创建一个计算属性,以便在 UserDefaults 更改时保存该值。
class TestClass: NSObject
static let shared = TestClass()
private override init()
super.init()
var status: Bool
get
return UserDefaults.standard.bool(forKey: "Status")
set
UserDefaults.standard.set(newValue, forKey: "Status")
【讨论】:
使用 UserDefaults 传递数据的好主意。单例类不是绝对必要的,对吧?它只能确保其他地方不存在多个实例?一个澄清 - 第一个功能仅在应用程序加载时开始执行,对吗?那么当App加载后状态发生变化时,它还能工作吗? @Yan 最好使用单例类,因为您不需要在每个视图控制器中为 TestClass 创建一个实例。如果您在 ViewController1 中创建一个 TestClass 实例,在 ViewController2 中创建另一个 TestClass 实例,那么现在两个状态属性都不相同。在应用加载时调用的 didFinishLaunchingWithOptions 方法。在 applicationWillTerminate 中保存值,在 didFinishLaunchingWithOptions 中获得保存的值 @Yan 检查更新的答案。通过使用计算属性,您无需将值保存在 applicationWillTerminate、applicationDidEnterBackground 中。每当您更改其值时,它都会自动保存。而且您不需要在 didFinishLaunchingWithOptions 中检索保存的值。当您尝试获取该值时,它会自动从 UserDefaults 中检索。【参考方案2】:正如其他人已经提到的,您可以忽略applicationWillTerminate
。
要在应用进入后台时得到通知,只需在视图控制器中添加一个观察者。
但是,我建议观察willResignActive
,而不是didEnterBackground
。
在viewDidLoad
中添加观察者一次
override func viewDidLoad()
super.viewDidLoad()
NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: nil) notification in
// save the properties
或者,如果您使用多个视图控制器,您可以在 viewWillAppear
中添加观察者并在 viewDidDisappear
中删除它
旁注:
如果您使用情节提要,切勿使用默认初始化程序 ViewController()
创建视图控制器。您将获得一个全新的实例,它不是故事板实例。
【讨论】:
以上是关于如何在 AppDelegate 和 ViewController 之间共享属性,并在 App 终止前保存的主要内容,如果未能解决你的问题,请参考以下文章
AppDelegate.swift 如何在 Xcode 6.3 中替换 AppDelegate.h 和 AppDelegate.m