ios - 在继续 swift 之前等待后台请求在 Alamofire 中完成并加载数组

标签 ios swift alamofire

我知道这里还有另一个问题,但没有人明确回答,也没有公认的答案。我有一个方法 loadDetail,它使用 UIBackgroundFetchResult 接受一个 completionHandler。当我选择一个单元格以从数组中加载该单元格的详细数据时,将调用此方法。调用此方法时,我希望调用它的方法等到 detailResults 数组被填充后再继续。我该怎么做,我做错了什么?

func loadDetail(urlPath: String, completionHandler: ((UIBackgroundFetchResult)     -> Void)!){
    Alamofire.request(.GET, urlPath)
        .responseJSON { _, _, result in
            switch result {
            case .Success(let data):
                let jsonObj = JSON(data)
                if let data = jsonObj["results"].arrayValue as [JSON]? {
                    //array is filled in the line below
                    self.detailResults = data
                    self.collectionView.reloadData()
                }
            case .Failure(_, let error):
                print("Request failed with error: \(error)")
            }
    }
    completionHandler(UIBackgroundFetchResult.NewData)
    print("Background Fetch Complete")
}

这是从中调用 loadDetail 的 collectionView 方法,您可以在调用它的地方看到关于我希望它执行的操作的注释。

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    let data = results?[indexPath.row]
    let detailData: JSON
    var testString: String = ""
    let vc: DetailBrowseViewController = self.storyboard?.instantiateViewControllerWithIdentifier("DetailBrowseViewController") as! DetailBrowseViewController

    if let titleString = data?["title"] {
        vc.titleString = titleString.stringValue
        testString = titleString.stringValue
        testString = testString.stringByReplacingOccurrencesOfString(" ", withString: "-")
        testString = testString.lowercaseString
        reusableUrl.replaceRange(Range<String.Index>(start: reusableUrl.startIndex.advancedBy(146), end: reusableUrl.startIndex.advancedBy(146)), with: testString)

        self.loadDetail(reusableUrl, completionHandler:{(UIBackgroundFetchResult) -> Void in
            //I want this collectionView method to somehow pause and wait until the detailResults array is filled and then continue
            print("success")
        })
    }

    detailData = (detailResults?[indexPath.row])!

    if let priceString = detailResults?[indexPath.row]["price"] {
        print(detailData)
        vc.priceString = priceString.stringValue
    }
    self.navigationController?.pushViewController(vc, animated: true)
}

问题是,loadDetail 方法直接通过,没有等待,导致在 collectionView 方法中调用时数组为 nil。

最佳答案

据我了解,当 self.detailResults 中填充了来自响应的 JSON 数据时,您需要调用 completionHandler

我会试着弄清楚我们的主要想法: - 仅在数据解析成功时调用competitionHandler - 将必要的代码(应该等待响应)移动到已经加载数据的地方。

首先,您需要将 completionHandler 调用移动到 .Success case block 的末尾。如果响应失败,我认为您不需要继续前进。

所以结果将是:

func loadDetail(urlPath: String, completionHandler: ((UIBackgroundFetchResult)     -> Void)!){
    Alamofire.request(.GET, urlPath)
        .responseJSON { _, _, result in
            switch result {
            case .Success(let data):
                let jsonObj = JSON(data)
                if let data = jsonObj["results"].arrayValue as [JSON]? {
                    //array is filled in the line below
                    self.detailResults = data
                    self.collectionView.reloadData()
                    completionHandler(UIBackgroundFetchResult.NewData)
                }
            case .Failure(_, let error):
                print("Request failed with error: \(error)")
            }
    }

    print("Background Fetch Complete")
}

然后你需要将相关代码(应该等待响应)移动到completionHandler,如下所示:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    let data = results?[indexPath.row]
    let detailData: JSON
    var testString: String = ""
    let vc: DetailBrowseViewController = self.storyboard?.instantiateViewControllerWithIdentifier("DetailBrowseViewController") as! DetailBrowseViewController

    if let titleString = data?["title"] {
        vc.titleString = titleString.stringValue
        testString = titleString.stringValue
        testString = testString.stringByReplacingOccurrencesOfString(" ", withString: "-")
        testString = testString.lowercaseString
        reusableUrl.replaceRange(Range<String.Index>(start: reusableUrl.startIndex.advancedBy(146), end: reusableUrl.startIndex.advancedBy(146)), with: testString)

        self.loadDetail(reusableUrl, completionHandler:{(UIBackgroundFetchResult) -> Void in
            //I want this collectionView method to somehow pause and wait until the detailResults array is filled and then continue
            print("success")
            detailData = (detailResults?[indexPath.row])!

            if let priceString = detailResults?[indexPath.row]["price"] {
                print(detailData)
                vc.priceString = priceString.stringValue
            }
            self.navigationController?.pushViewController(vc, animated: true)
        })
    }
} 

关于ios - 在继续 swift 之前等待后台请求在 Alamofire 中完成并加载数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32996515/

相关文章:

iphone - UITableView 未刷新

android - 几个月后 Google Ads 突然停止工作 [Android][iOS][Flutter]

ios - 如何使用 Swift 从 Assets 中加载特定图像

ios - APNS注册及其生命周期

ios - SwiftUI - 数据源为空时动态列表过滤动画飞到右侧

带`(反引号)的 Swift 变量名

iphone - 访问其他类中的变量时为空值(组合导航和选项卡 Controller )

ios - 无法在CollectionViewCell中设置imageView

ios - 使用 Alamofire、ImageLoader 在 swift 中解析 Json 来解析键值以及具有图像的 TableView 中的对象

iOS:JSON 上传进度