Swift 如何在后台自动触发代码?
How to automatically trigger code in background in Swift?
初学者尝试创建一个应用程序,为用户提供一个随机的“每日词汇”。
通过测试,我意识到用户必须每天打开该应用程序才能手动触发函数isRefreshRequired()
(检索新词和更新用户界面和通知内容)。但我需要自动完成此操作,无论用户是否打开应用程序。
这可能吗?我被困在使用哪种方法之间:
NSCalendarDayChanged. I found this useful answer 但我不确定它会在哪里实施?如果我使用它 applicationDidFinishLaunching,函数 calendarDayDidChange() 会在哪里被调用?在 viewDidLoad()?
significantTimeChangeNotification() - 可能是更好的方法?同样,不确定如何实际实施以及在何处实施。该文件还说:
If the the device is asleep when the day changes, this notification
will be posted on wakeup.
wakeup是指应用重新打开的时候吗?因为我希望 isRefreshRequired() 函数即使在用户没有触摸应用程序的情况下也能执行。
- Background App Refresh: 这似乎没有用,因为它需要 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()")
}
}
}
您正在尝试做的是在应用程序关闭或在后台时调用一个函数。退后一步,用户此时实际上并未使用您的应用程序。因此,您的应用也不应该真正成为 运行 函数。我相信这是故意的,以便 phone 可以将资源分配给用户正在积极使用的 apps/functions。
所以没有办法在应用程序关闭时只调用一个函数。但是偏离你上面的观点:
我认为使用 applicationDidBecomeActive 或 applicationDidFinishLaunching 可能是您最好的选择。这些是 AppDelegate 中的函数,您可以直接调用方法中的函数。 applicationDidBecomeActive 将在每次应用程序出现在屏幕上时执行。如果你只需要在一个屏幕上使用它,你可以调用 ViewController 的 viewDidAppear / viewWillAppear 来代替。
我不知道任何关于 significantTimeChangeNotification 的事情,所以我不想告诉你它不起作用,但我猜如果应用程序关闭,通知将不会执行。
后台应用程序刷新基本上就是您想要做的,但是,即使您实现了它..它只会在应用程序处于 background[=27= 时执行].如果应用程序完全关闭,则不会调用后台提取。所以我假设大多数时候它不会被调用。
初学者尝试创建一个应用程序,为用户提供一个随机的“每日词汇”。
通过测试,我意识到用户必须每天打开该应用程序才能手动触发函数isRefreshRequired()
(检索新词和更新用户界面和通知内容)。但我需要自动完成此操作,无论用户是否打开应用程序。
这可能吗?我被困在使用哪种方法之间:
NSCalendarDayChanged. I found this useful answer 但我不确定它会在哪里实施?如果我使用它 applicationDidFinishLaunching,函数 calendarDayDidChange() 会在哪里被调用?在 viewDidLoad()?
significantTimeChangeNotification() - 可能是更好的方法?同样,不确定如何实际实施以及在何处实施。该文件还说:
If the the device is asleep when the day changes, this notification will be posted on wakeup.
wakeup是指应用重新打开的时候吗?因为我希望 isRefreshRequired() 函数即使在用户没有触摸应用程序的情况下也能执行。
- Background App Refresh: 这似乎没有用,因为它需要 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()")
}
}
}
您正在尝试做的是在应用程序关闭或在后台时调用一个函数。退后一步,用户此时实际上并未使用您的应用程序。因此,您的应用也不应该真正成为 运行 函数。我相信这是故意的,以便 phone 可以将资源分配给用户正在积极使用的 apps/functions。
所以没有办法在应用程序关闭时只调用一个函数。但是偏离你上面的观点:
我认为使用 applicationDidBecomeActive 或 applicationDidFinishLaunching 可能是您最好的选择。这些是 AppDelegate 中的函数,您可以直接调用方法中的函数。 applicationDidBecomeActive 将在每次应用程序出现在屏幕上时执行。如果你只需要在一个屏幕上使用它,你可以调用 ViewController 的 viewDidAppear / viewWillAppear 来代替。
我不知道任何关于 significantTimeChangeNotification 的事情,所以我不想告诉你它不起作用,但我猜如果应用程序关闭,通知将不会执行。
后台应用程序刷新基本上就是您想要做的,但是,即使您实现了它..它只会在应用程序处于 background[=27= 时执行].如果应用程序完全关闭,则不会调用后台提取。所以我假设大多数时候它不会被调用。