ios - 如何在 Swift 中自动触发后台代码?
问题描述
初学者尝试创建一个应用程序,为用户提供随机的“每日词汇”。
通过测试,我意识到该应用程序必须由用户每天打开才能手动触发功能isRefreshRequired()
(检索新词并更新用户界面和通知内容)。但无论用户是否打开应用程序,我都需要自动完成此操作。
这甚至可能吗?我被困在使用哪些方法之间:
NSCalendarDayChanged。我找到了这个有用的答案,但我不确定它会在哪里实施?如果我使用它 applicationDidFinishLaunching,那么函数 calendarDayDidChange() 会在哪里被调用?在 viewDidLoad() 中?
significantTimeChangeNotification() - 可能是更好的方法?同样,不确定如何实际实现这一点以及在哪里实现。该文件还说:
如果设备在白天变化时处于睡眠状态,则此通知将在唤醒时发布。
唤醒是否意味着重新打开应用程序?因为即使用户没有触摸应用程序,我也希望执行 isRefreshRequired() 函数。
- 后台应用刷新:这似乎没有用,因为它需要一个 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()")
}
}
}
解决方案
您要做的是在应用程序关闭或在后台调用一个函数。退后一步,用户此时实际上并没有使用您的应用程序。因此,因此,您的应用程序也不应该真正运行函数。我相信这是故意这样做的,以便手机可以将资源分配给用户正在积极使用的应用程序/功能。
因此,当应用程序关闭时,无法仅调用函数。但是从上面的观点出发:
我认为使用 applicationDidBecomeActive 或 applicationDidFinishLaunching 可能是您最好的选择。这些是 AppDelegate 中的函数,您可以直接调用方法中的函数。应用程序每次出现在屏幕上时都会执行 applicationDidBecomeActive。如果您只需要在一个屏幕上使用它,您可以只调用 ViewController 的 viewDidAppear / viewWillAppear 。
Idk 关于显着TimeChangeNotification 的任何事情,所以我不想告诉你它不起作用,但我猜如果应用程序关闭,通知将不会执行。
后台应用刷新基本上是您尝试做的事情,但是,即使您实现了它..它只会在应用程序是后台时执行。如果应用程序完全关闭,则不会调用后台提取。所以我会假设大多数时候它不会被调用。
推荐阅读
- python - 如何保存和恢复具有某些功能的数据是列表?
- databricks - 永久保留 Delta Lake 的 Delta log 事务数据
- c - 二维矩阵中的字符重新分配引发分段错误
- javascript - 封装在 VueJS 计算属性中时,JavaScript 对象的深度复制不起作用
- javascript - 将自定义 React 组件插入到带有 html 内容的 String 变量中
- microsoft-graph-api - 在 .net Graph SDK 中, Range().Clear() 给出了编译错误,并且不像文档中所说的那样工作
- javascript - 查找相同的数组,如果条件相同,我将在 Vue Js 上更新一个数组
- php - (sql injection)sqli-lab 15: where 子句中的不可理解的行为
- php - 致命错误:无法使用 isset,请改用空表达式
- react-native - 是否可以在不指定路由名称的情况下单步执行 React Navigation 堆栈导航器?