首页 > 解决方案 > 如何在 Swift 中自动触发后台代码?

问题描述

初学者尝试创建一个应用程序,为用户提供随机的“每日词汇”。

通过测试,我意识到该应用程序必须由用户每天打开才能手动触发功能isRefreshRequired()(检索新词并更新用户界面和通知内容)。但无论用户是否打开应用程序,我都需要自动完成此操作。

这甚至可能吗?我被困在使用哪些方法之间:

  1. NSCalendarDayChanged。我找到了这个有用的答案,但我不确定它会在哪里实施?如果我使用它 applicationDidFinishLaunching,那么函数 calendarDayDidChange() 会在哪里被调用?在 viewDidLoad() 中?

  2. significantTimeChangeNotification() - 可能是更好的方法?同样,不确定如何实际实现这一点以及在哪里实现。该文件还说:

如果设备在白天变化时处于睡眠状态,则此通知将在唤醒时发布。

唤醒是否意味着重新打开应用程序?因为即使用户没有触摸应用程序,我也希望执行 isRefreshRequired() 函数。

  1. 后台应用刷新:这似乎没有用,因为它需要一个 URLSession 并且用户可能禁用了后台刷新。对于一个只想给用户一个新词的应用程序来说似乎有点过分了!

有问题的代码:

    override func viewDidLoad() {
            super.viewDidLoad()
            
    isRefreshRequired()
        }

    func isRefreshRequired() {
                // if it is first time opening app
                if userDefaults.bool(forKey: "First Launch") == false {
                    //run code during first launch
                    _ = updateWordOfTheDay()
                    NotificationManager.askNotificationPermission()
                    print("First time opening app")
                    userDefaults.set(true, forKey: "First Launch")
                }
                else {
                    //run code after first launch
                    print("Not first time opening app")
                    userDefaults.set(true, forKey: "First Launch")
    
                    let lastAccessDate = userDefaults.object(forKey: "lastAccessDate") as? Date ?? Date()
                    userDefaults.set(Date(), forKey: "lastAccessDate")
    
                    // if it is the same day give the vocab picked for that day
                    if calendar.isDateInToday(lastAccessDate) {
                        readFromUserDefaults()
                        print("No refresh required as it is the same day as lastAccessDate which was \(lastAccessDate)")
                    }
                    else {
                        print("new day since lastAccessDate")
                        _ = updateWordOfTheDay()
                    }
    
                }
            }

    func sendNotification(using: ChineseVocab) {
        
        let center = UNUserNotificationCenter.current()
        center.removeAllDeliveredNotifications()
        center.removeAllPendingNotificationRequests()
        
let content = UNMutableNotificationContent()
        content.title = using.Chinese + " " + using.Pinyin
        content.body = using.Definition

}

    func saveToUserDefaults(with data: ChineseVocab) {
            let encoder = JSONEncoder()
            if let encoded = try? encoder.encode(data) {
                userDefaults.set(encoded, forKey: "selectedVocab")
            }
        }
    
         func readFromUserDefaults() {
            if let savedVocab = userDefaults.object(forKey: "selectedVocab") as? Data {
                let decoder = JSONDecoder()
                if let wordOfTheDay = try? decoder.decode(ChineseVocab.self, from: savedVocab) {
                updateLabels(using: wordOfTheDay)
                 NotificationManager.sendNotification(using: wordOfTheDay)
                    print("readFromUserDefaults() is working: \(wordOfTheDay)")
                } else {
                    print("unable to load readFromUserDefaults()")
                }
            }
        }

标签: iosswiftbackgroundrefresh

解决方案


您要做的是在应用程序关闭或在后台调用一个函数。退后一步,用户此时实际上并没有使用您的应用程序。因此,因此,您的应用程序也不应该真正运行函数。我相信这是故意这样做的,以便手机可以将资源分配给用户正在积极使用的应用程序/功能。

因此,当应用程序关闭时,无法仅调用函数。但是从上面的观点出发:

  1. 我认为使用 applicationDidBecomeActive 或 applicationDidFinishLaunching 可能是您最好的选择。这些是 AppDelegate 中的函数,您可以直接调用方法中的函数。应用程序每次出现在屏幕上时都会执行 applicationDidBecomeActive。如果您只需要在一个屏幕上使用它,您可以只调用 ViewController 的 viewDidAppear / viewWillAppear 。

  2. Idk 关于显着TimeChangeNotification 的任何事情,所以我不想告诉你它不起作用,但我猜如果应用程序关闭,通知将不会执行。

  3. 后台应用刷新基本上是您尝试做的事情,但是,即使您实现了它..它只会在应用程序是后台时执行。如果应用程序完全关闭,则不会调用后台提取。所以我会假设大多数时候它不会被调用。


推荐阅读