应用程序使用后台提取在Collectionview的reloadData()崩溃

时间:2016-05-19 08:44:24

标签: swift uicollectionview 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")
    }
}

2 个答案:

答案 0 :(得分:0)

尝试在启动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)
                        }
                    }
    }

答案 1 :(得分:0)

不要再次初始化PublicationOverviewController(),因为它会为您提供该视图的新实例,而您不会获得引用的collectionView。此外,在viewDidLoad:接听电话之前,您将获得所有UI控件。

示例:

let *controller : PublicationOverviewController = PublicationOverviewController()
// controller.collectionView will be nil here because view hasn't loaded yet

您可以做什么在applicationDidBecomeActive:方法中发布通知,在observePublicationOverviewController发布通知,然后在相应方法中重新加载collectionView