UITableView willDisplay 在调用 API 分页时不断调用自身,问题是异步 API 调用

UITableView willDisplay keeps calling itself when calling the API pagination, Issue is with async API Calling

我正在使用 MVVM,这个表视图委托在 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)
        }
    }
}

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

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

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

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

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

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

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

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