我知道这里还有另外一个问题,但是没有人能够清楚地回答这个问题,而且没有接受的答案。我有一个方法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。
答案 0 :(得分:4)
根据我的理解,当completionHandler
填充了来自回复的JSON数据时,您需要致电self.detailResults
。
我会试着想出我们的主要想法:
- 仅在成功解析数据时调用competitionHandler
- 将必要的代码(应该等待响应)移动到已经加载数据的地方。
首先,您需要将completionHandler
调用移至.Success案例块的末尾。如果响应失败,我认为你不需要前进。
结果将是:
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)
})
}
}