应用程序在后台获取的 Collectionview 的 reloadData() 处崩溃
App crashes at reloadData() for Collectionview with a background fetch
所以我正在进行后台获取,之后我想更新 UI。后台获取本身(数据库)有效,但是当我想更新 UI 时,我遇到了崩溃 unexpectedly found nil while unwrapping an Optional value
根据我的 xCode self.newestPublicationsCollectionView.reloadData()
是在 updateCollections() 函数中发生崩溃的地方。
func updateCollections() {
// get latest data from Database
latestPublications = getNewestPublications()
self.newestPublicationsCollectionView.reloadData()
self.newestPublicationsCollectionView.layoutIfNeeded()
// fix wrong content height
self.newestPublicationsCollectionViewHeight.constant = self.newestPublicationsCollectionView.collectionViewLayout.collectionViewContentSize().height
}
AppDelegate 中的其他代码:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatch_async(dispatch_get_main_queue()) {
fetchViewController.updateCollections()
}
completionHandler(.NewData)
}
}
我的 PublicationOverviewController 中的 .fetch
func fetch(completion: () -> Void) {
PublicationFetcher.shared.fetchAllPublications()
completion()
}
我以为崩溃是因为我需要在主线程上使用 UI,但这并没有帮助。任何输入都会很好。
详情:
在我的 PublicationFetcher.shared.fetchAllPublications() 中,我执行以下操作:
- 从后端获取数据
dispatch_async(dispatch_get_main_queue()) { () -> Void in NSNotificationCenter.defaultCenter().postNotificationName("RELOAD_NOTIFICATION", object: nil) }
在那个重新加载通知下我做了一个updateCollections()
Swift 3:
DispatchQueue.global(attributes: .qosBackground).async {
print("This is run on the background queue")
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
}
在开始 UI 操作之前,尝试为您的应用提供 30 秒的后台获取超时时间,这对您的后台网络连接有帮助:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue()) {
<#code to be executed after a specified delay#>
fetchViewController.updateCollections()
completionHandler(.NewData)
}
}
你也可以使用这个功能:
func dispatchDelay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
称它为这个例子:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatchDelay(25) { // put what you want
// this is main-thread queue
fetchViewController.updateCollections()
completionHandler(.NewData)
}
}
}
不要再次初始化 PublicationOverviewController()
,因为它会为您提供该视图的新实例,而您不会获得引用的 collectionView
。此外,在 viewDidLoad:
接到电话之前,您将获得所有 UI 控件 nil。
示例:
let *controller : PublicationOverviewController = PublicationOverviewController()
// controller.collectionView will be nil here because view hasn't loaded yet
你可以做什么 Post 在 applicationDidBecomeActive:
方法中的通知和 observe
在 PublicationOverviewController
中的通知,然后在相应的方法中重新加载你的 collectionView
。
所以我正在进行后台获取,之后我想更新 UI。后台获取本身(数据库)有效,但是当我想更新 UI 时,我遇到了崩溃 unexpectedly found nil while unwrapping an Optional value
根据我的 xCode self.newestPublicationsCollectionView.reloadData()
是在 updateCollections() 函数中发生崩溃的地方。
func updateCollections() {
// get latest data from Database
latestPublications = getNewestPublications()
self.newestPublicationsCollectionView.reloadData()
self.newestPublicationsCollectionView.layoutIfNeeded()
// fix wrong content height
self.newestPublicationsCollectionViewHeight.constant = self.newestPublicationsCollectionView.collectionViewLayout.collectionViewContentSize().height
}
AppDelegate 中的其他代码:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatch_async(dispatch_get_main_queue()) {
fetchViewController.updateCollections()
}
completionHandler(.NewData)
}
}
我的 PublicationOverviewController 中的 .fetch
func fetch(completion: () -> Void) {
PublicationFetcher.shared.fetchAllPublications()
completion()
}
我以为崩溃是因为我需要在主线程上使用 UI,但这并没有帮助。任何输入都会很好。
详情:
在我的 PublicationFetcher.shared.fetchAllPublications() 中,我执行以下操作:
- 从后端获取数据
dispatch_async(dispatch_get_main_queue()) { () -> Void in NSNotificationCenter.defaultCenter().postNotificationName("RELOAD_NOTIFICATION", object: nil) }
在那个重新加载通知下我做了一个updateCollections()
Swift 3:
DispatchQueue.global(attributes: .qosBackground).async {
print("This is run on the background queue")
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
}
在开始 UI 操作之前,尝试为您的应用提供 30 秒的后台获取超时时间,这对您的后台网络连接有帮助:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue()) {
<#code to be executed after a specified delay#>
fetchViewController.updateCollections()
completionHandler(.NewData)
}
}
你也可以使用这个功能:
func dispatchDelay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
称它为这个例子:
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
let fetchViewController = PublicationOverviewController()
fetchViewController.fetch {
dispatchDelay(25) { // put what you want
// this is main-thread queue
fetchViewController.updateCollections()
completionHandler(.NewData)
}
}
}
不要再次初始化 PublicationOverviewController()
,因为它会为您提供该视图的新实例,而您不会获得引用的 collectionView
。此外,在 viewDidLoad:
接到电话之前,您将获得所有 UI 控件 nil。
示例:
let *controller : PublicationOverviewController = PublicationOverviewController()
// controller.collectionView will be nil here because view hasn't loaded yet
你可以做什么 Post 在 applicationDidBecomeActive:
方法中的通知和 observe
在 PublicationOverviewController
中的通知,然后在相应的方法中重新加载你的 collectionView
。