如何使用 Swift 配置后台应用刷新?
Posted
技术标签:
【中文标题】如何使用 Swift 配置后台应用刷新?【英文标题】:How to configure Background App Refresh using Swift? 【发布时间】:2017-10-31 21:48:09 【问题描述】:我有以下功能可以在我的 SeachVC (UIViewController) 中下载 JSON 数据,效果很好。
func downloadJSON()
guard let url = URL(string: "myURL") else return
URLSession.shared.dataTask(with: url) (data, response, err) in
guard let data = data else return
do
let downloadedCurrencies = try JSONDecoder().decode([Currency].self, from: data)
// Adding downloaded data into Local Array
Currencies = downloadedCurrencies
catch let jsonErr
print("Here! Error serializing json", jsonErr)
.resume()
为了实现后台应用刷新,我在 App Delegate 中添加了以下功能;
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
// Override point for customization after application launch.
// Background App Refresh Config
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
if let VC = window?.rootViewController as? SearchVC
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
但是,当我在模拟器上模拟后台应用刷新时,我收到警告:
警告:应用程序委托收到了对 -application:performFetchWithCompletionHandler: 的调用,但从未调用过完成处理程序。
我将在哪里实现完成处理程序以及如何实现?
谢谢
【问题讨论】:
【参考方案1】:如果需要,您需要将下载代码从视图控制器移动到另一个类,或者至少修改您当前的后台刷新方法以实例化视图控制器。当您的应用尚未在前台启动时,可以触发后台刷新,因此if let
将失效。
考虑问题中的代码:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
if let VC = window?.rootViewController as? SearchVC
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
如果 if let...
没有通过,那么您退出函数而不调用 completionHandler
,因此您会收到 runtime 警告,指出未调用完成处理程序。
您可以修改您的代码以在 else
案例中包含对 completionHandler
的调用,但在这种情况下不会进行任何提取:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
if let VC = window?.rootViewController as? SearchVC
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
else
completionHandler(.noData)
或者,如果需要,您可以实例化视图控制器(或者我会建议另一个数据获取类):
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
let vc = (window?.rootViewController as? SearchVC) ?? SearchVC()
// Update JSON data
vc.downloadJSON()
completionHandler(.newData)
您还应该修改您的 downloadJSON
函数以包含一个完成处理程序参数,当 JSON 下载完成时您将调用该参数。这将让您在实际下载数据后调用后台获取完成处理程序:
func downloadJSON(completion: ((Bool,Error?) -> Void )? = nil))
guard let url = URL(string: "myURL") else
completion?(false, nil)
return
URLSession.shared.dataTask(with: url) (data, response, err) in
guard nil == err else
completion?(false, err)
return
guard let data = data else
completion?(false, nil)
return
do
let downloadedCurrencies = try JSONDecoder().decode([Currency].self, from: data)
// Adding downloaded data into Local Array
Currencies = downloadedCurrencies
completion(true,nil)
catch let jsonErr
print("Here! Error serializing json", jsonErr)
completion?(false,jsonErr)
.resume()
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
let vc = (window?.rootViewController as? SearchVC) ?? SearchVC()
// Update JSON data
vc.downloadJSON() (newData,error) in
if let err = error
NSLog("Background fetch error: \(err.localizedDescription)")
completionHandler(.fail)
else
completionHandler(newData ? .newData:.noData)
2019 年 9 月更新
请注意,ios 13 引入了新的后台获取和处理功能。更多详情请参考WWDC session
【讨论】:
感谢您的出色回答。我是新手,所以请原谅我的问题。如何将 completionHandler 添加到我的 downloadJSON 中?哦,你也加了。非常感谢!将实施您的输入!真的很感激! 最后的部分代码给出了一个错误:参数传递给调用,该调用在 vc.downloadJSON() (error) in 的“”上不接受任何参数 那是因为您需要在下载函数中添加完成处理程序参数 - 请参阅我编辑的答案 完美运行。没有错误。我希望我也可以将您的问题标记为答案。非常感谢您的宝贵时间!completionHandler
是系统调用委托方法时提供的。完成后,您有责任使用 fetch 的结果调用它。 .newData
表示获取了新数据。 iOS 使用该结果来确定您的应用应该多久以及何时有机会执行后台提取。【参考方案2】:
这可能是因为您没有在 else 情况下调用 completionHandler
(这永远不会发生,但编译器不知道)
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
if let VC = window?.rootViewController as? SearchVC
// Update JSON data
VC.downloadJSON()
completionHandler(.newData)
else
completionHandler(.failed)
【讨论】:
警告消失了。谢谢! 其实这是iOS发出的运行时警告,而不是编译器,因为确实发生了;if
测试失败,因为视图控制器在后台不可用。在 else
中添加对完成处理程序的调用将导致警告消失,因为完成处理程序被调用,但没有发生下载。以上是关于如何使用 Swift 配置后台应用刷新?的主要内容,如果未能解决你的问题,请参考以下文章
即使应用程序在后台运行,如何使用 swift 在 ios 中获取位置更新
在swift中,当应用程序进入后台时,如何使用依赖注入保存变量?
如何使用 Swift 在 Apple Watch 上添加下拉刷新功能