如何在 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 终止前保存的主要内容,如果未能解决你的问题,请参考以下文章

使用 restkit 和核心数据的最佳实践

alloc init 不会在其中加载组件

AppDelegate.swift 如何在 Xcode 6.3 中替换 AppDelegate.h 和 AppDelegate.m

以编程方式将 leftBarButtonItem 添加到应用程序

present的时候是可以直接回到第一个viewcon的

如何从 appdelegate 呈现和关闭模态视图?