2015-10-07 5 views
0

Я знаю, что здесь есть еще один вопрос, но никто не ответил однозначно и не было ответа. У меня есть метод loadDetail, который принимает завершениеHandler, используя UIBackgroundFetchResult. Этот метод вызывается, когда я выбираю ячейку для загрузки подробных данных для этой ячейки из массива. Когда этот метод вызывается, я хочу, чтобы метод вызывал его, чтобы ждать, пока массив detailResults не будет заполнен, прежде чем продолжить. Как я могу это сделать и что я делаю неправильно?Подождите, пока запрос фона будет завершен в Alamofire, и массив загрузится, прежде чем продолжить быстро

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") 
} 

Вот метод CollectionView, что loadDetail вызывается, вы можете увидеть свой комментарий, где он называется, относящиеся к тому, что я хотел бы это сделать.

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.

ответ

4

Как я понимаю, вам нужно позвонить completionHandler, когда self.detailResults заполняется данными JSON от ответа.

Я попытаюсь понять нашу основную идею: - вызов 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) 
     }) 
    } 
} 
+0

это работает, спасибо. – km95

Смежные вопросы