应用程序在后台获取的 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() 中,我执行以下操作:

在那个重新加载通知下我做了一个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: 方法中的通知和 observePublicationOverviewController 中的通知,然后在相应的方法中重新加载你的 collectionView