【问题标题】:UITableView willDisplay keeps calling itself when calling the API pagination, Issue is with async API CallingUITableView willDisplay 在调用 API 分页时不断调用自身,问题在于异步 API 调用
【发布时间】:2021-07-24 06:37:13
【问题描述】:

我正在使用 MVVM,而这个 tableview 委托在 ViewController 中 问题是因为 API 调用函数使用 ViewModel 对象

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if indexPath.row == photosVM.albumData.photos!.photo!.count - 1 {
        if photosVM.albumData.photos!.pages! >= photosVM.albumData.photos!.page! {
            spinner.color = UIColor.FlickrAlbum_theme
            spinner = UIActivityIndicatorView(style: .medium)
            spinner.startAnimating()
            spinner.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: tableView.bounds.width, height: CGFloat(44))
            tblPhotos.tableFooterView = spinner
            tblPhotos.tableFooterView?.isHidden = false
                //Calling search API with search keywords
                photosVM.getPhotos(pageNumber: photosVM.albumData.photos!.page! + 1, searchText: txtSearch.text!) { [self] (status) in
                    lblDescription.text = txtSearch.text
                    if status == "success" {
                        lblDescription.text = txtSearch.text
                        tblPhotos.reloadData()
                    }
                    else {
                        //showing error message
                        showAlert(message: status)
                    }
                }
            spinner.stopAnimating()
            tblPhotos.tableFooterView = nil
            tblPhotos.tableFooterView?.isHidden = true
        }
   }

这是我的 ViewModel,其中我有一个调用 API 并将数据绑定到视图控制器的功能

func getPhotos(pageNumber: Int = 1, completion: @escaping (String) -> Void) {
    let params = GetPhotosBody()
    params.format = "json"
    params.apiKey = Constants.apiKey
    params.nojsoncallback = 1
    params.page = pageNumber
    params.text = ""
    params.contentType = 1
    ServerManager.getAllPhotos(params: params) { [self] (status, data) in
        if status == "success" {
            if pageNumber == 1 {
                albumData = data
            }
            else {
                 albumData.photos?.page = data?.photos?.page!
                 albumData.photos?.photo?.append(contentsOf: (data!.photos!.photo!))
            }
            //Cache Data
             DataCache.instance.write(object: albumData.toJSON() as NSCoding, forKey: CacheValue.photos)
        }
        if let photos = DataCache.instance.readObject(forKey: CacheValue.photos) {
            albumData = Mapper<FlickrAlbumPhotosResponse>().map(JSONObject: photos)
       }
       else {
           albumData = nil
       }
        completion(status)
    }
}

这是 API 调用管理器,我正在使用 completionblock 来处理异步方法

public static func getAllPhotos(params: GetPhotosBody, completion: @escaping (String ,FlickrAlbumPhotosResponse?) -> Void) {
    //creating URL
    //addingPercentEncoding is used for encoding the url string to support text with spaces
    let url = "\(Constants.baseURL)\(FlickrAlbumEndpoints.getPhotos.rawValue)&format=\(String(describing: params.format!))&nojsoncallback=\(String(describing: params.nojsoncallback!))&api_key=\(String(describing: params.apiKey!))&page=\(String(describing: params.page!))".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
    //creating request
    var request = URLRequest(url: URL(string: url)!)
    request.httpMethod = HTTPMethod.get.rawValue
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    //Making request to the server to call the API
    Alamofire.request(request).responseObject { (response: DataResponse<FlickrAlbumPhotosResponse>) in
        //Check the response of the API
        switch response.result {
            case .success:
                let data = response.result.value
                completion("success",data)
            case .failure(let error):
                completion(error.localizedDescription, nil)
        }
    }
}

每当我关闭互联网时,它都会一次又一次地显示错误消息,因为它一直在调用将显示委托。 如果我以错误的方式使用 MVVM,请告诉我并提出您的建议。谢谢

【问题讨论】:

    标签: ios swift uitableview mvvm delegates


    【解决方案1】:

    我强烈怀疑当 api 调用失败时(因为没有互联网),您正在将一些缓存数据分配给您的视图模型数组。分配它会触发视图控制器中的绑定函数,该函数会重新加载 tableview,因此 api 调用再次进入无限循环。

    从您的 api 函数中删除缓存分配,它应该可以正常工作。

    【讨论】:

      【解决方案2】:

      它一直显示错误消息,因为表在 getSearchPhotos 完成块上一次又一次地重新加载其数据。

      重新加载数据将调用表视图委托,然后此过程将循环。

      photosVM.getSearchPhotos(pageNumber: photosVM.albumData.photos!.page! + 1, searchText: txtSearch.text!) { [self] (status) in
          lblDescription.text = txtSearch.text
          tblPhotos.reloadData() // why reload here?
      
          // the rest of the code
      }
          
      

      取消注释第一个重新加载代码,如果调用API成功则重新加载数据。

      【讨论】:

      • 我删除了,但错误仍然相同:(
      • 其实问题出在 API 的异步调用上。我正在从 VC 调用 ViewModel 函数,而 ViewModel 函数正在调用 API 函数。
      • 它应该是这样工作的,VC不应该直接调用API。只是好奇,你的photosVM.albumData.photos!.photo! 结构是什么样的?
      • 它是一组具有其他属性的图像。该模型工作得很好。有没有其他方法可以使用 MVVM 从 VC 调用 API。
      • 顺便说一下,当我直接从 VC 调用 API 函数时,它工作正常。问题是从 viewmodel 调用 API 函数。
      【解决方案3】:

      我刚刚从 ViewModel 函数中删除了这些行,现在它工作正常。

       if let photos = DataCache.instance.readObject(forKey: CacheValue.photos) {
              albumData = Mapper<FlickrAlbumPhotosResponse>().map(JSONObject: photos)
         }
         else {
             albumData = nil
         }
      

      现在,我在 ViewModel 初始化时处理了那个缓存,它在构造函数中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多