首页 文章

限制tableView中显示的单元格数量,滚动到最后一个单元格时加载更多单元格

提问于
浏览
0

我正在尝试设置一个只显示特定数量单元格的表格视图 . 一旦显示该单元格,用户就可以继续滚动以显示更多单元格 . 截至目前,我正在检索要在viewDidLoad中显示的所有JSON数据并将它们存储在数组中 . 仅举例来说,我试图仅首先显示2个单元格,一个用户滚动到屏幕底部,下一个单元格将出现 . 到目前为止这是我的代码:

class DrinkViewController: UIViewController {

  @IBOutlet weak var drinkTableView: UITableView!


  private let networkManager = NetworkManager.sharedManager

  fileprivate var totalDrinksArray: [CocktailModel] = []
  fileprivate var drinkImage: UIImage?

  fileprivate let DRINK_CELL_REUSE_IDENTIFIER = "drinkCell"
  fileprivate let DRINK_SEGUE = "detailDrinkSegue"

  var drinksPerPage = 2
  var loadingData = false

  override func viewDidLoad() {
    super.viewDidLoad()

    drinkTableView.delegate = self
    drinkTableView.dataSource = self

    networkManager.getJSONData(function: urlFunction.search, catagory: urlCatagory.cocktail, listCatagory: nil, drinkType: "margarita", isList: false, completion: { data in

      self.parseJSONData(data)

    })
  }

}

extension DrinkViewController {

  //MARK: JSON parser
  fileprivate func parseJSONData(_ jsonData: Data?){
    if let data = jsonData {

      do {
        let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String : AnyObject]//Parses data into a dictionary

        // print(jsonDictionary!)
        if let drinkDictionary = jsonDictionary!["drinks"] as? [[String: Any]] {
          for drink in drinkDictionary {
            let drinkName = drink["strDrink"] as? String ?? ""
            let catagory = drink["strCategory"] as? String
            let drinkTypeIBA = drink["strIBA"] as? String
            let alcoholicType = drink["strAlcoholic"] as? String
            let glassType = drink["strGlass"] as? String
            let drinkInstructions = drink["strInstructions"] as? String
            let drinkThumbnailUrl = drink["strDrinkThumb"] as? String

            let cocktailDrink = CocktailModel(drinkName: drinkName, catagory: catagory, drinkTypeIBA: drinkTypeIBA, alcoholicType: alcoholicType, glassType: glassType, drinkInstructions: drinkInstructions, drinkThumbnailUrl: drinkThumbnailUrl)

            self.totalDrinksArray.append(cocktailDrink)
          }
        }
      } catch let error as NSError {
        print("Error: \(error.localizedDescription)")

      }
    }

    DispatchQueue.main.async {
      self.drinkTableView.reloadData()
    }
  }


  //MARK: Image Downloader
  func updateImage (imageUrl: String, onSucceed: @escaping () -> Void, onFailure: @escaping (_ error:NSError)-> Void){
    //named imageData because this is the data to be used to get image, can be named anything
    networkManager.downloadImage(imageUrl: imageUrl, onSucceed: { (imageData) in
      if let image = UIImage(data: imageData) {
       self.drinkImage = image
      }
      onSucceed()//must call completion handler
    }) { (error) in
      onFailure(error)
    }
  }
}


//MARK: Tableview Delegates
extension DrinkViewController: UITableViewDelegate, UITableViewDataSource {

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    //return numberOfRows
    return drinksPerPage
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = drinkTableView.dequeueReusableCell(withIdentifier: DRINK_CELL_REUSE_IDENTIFIER) as! DrinkCell


    //get image from separate url
    if let image = totalDrinksArray[indexPath.row].drinkThumbnailUrl{//index out of range error here
      updateImage(imageUrl: image, onSucceed: {
        if let currentImage = self.drinkImage{
          DispatchQueue.main.async {
            cell.drinkImage.image = currentImage
          }
        }
      }, onFailure: { (error) in
        print(error)
      })
    }
    cell.drinkLabel.text = totalDrinksArray[indexPath.row].drinkName
    return cell
  }

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let image = totalDrinksArray[indexPath.row].drinkThumbnailUrl{
      updateImage(imageUrl: image, onSucceed: {
      }, onFailure: { (error) in
        print(error)
      })
    }
    performSegue(withIdentifier: DRINK_SEGUE, sender: indexPath.row)
  }


  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let lastElement = drinksPerPage
      if indexPath.row == lastElement {
         self.drinkTableView.reloadData()
      }
  }
}

我看到这篇文章:tableview-loading-more-cell-when-scroll-to-bottom并实现了willDisplay函数但是收到"index out of range"错误 .

1 回答

  • 0

    如果你一次性获得所有结果,你能告诉我为什么你这样做,那么你不必限制你的显示,因为它是由tableview自动管理的 . 在tableview中,所有单元格都被重用,因此不存在内存问题 . UITableViewCell将在显示时创建 .

    因此无需限制细胞计数 .

    I dont now what you are doing in your code but:

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
         let lastElement = drinksPerPage // no need to write this line
         if indexPath.row == lastElement { // if block will never be executed since indexPath.row is never equal to drinksPerPage.
         // As indexPath starts from zero, So its value will never be 2.
            self.drinkTableView.reloadData()
      }
    }
    

    您的应用可能会崩溃,因为您可能只从服务器获得一个项目 .

    If you seriously want to load more then you can try this code:

    声明 numberOfItem 应该等于 drinksPerPage

    var numberOfItem = drinksPerPage
    
       func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
         //return numberOfRows
         return numberOfItem
       }
    
       func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
         if indexPath.row == numberOfItem - 1 { 
            if self.totalDrinksArray.count > numberOfItem {
               let result = self.totalDrinksArray.count - numberOfItem
               if result > drinksPerPage {
                  numberOfItem = numberOfItem + drinksPerPage
               }
               else {
                  numberOfItem = result
               }   
               self.drinkTableView.reloadData()
            }
         }
       }
    

相关问题