【问题标题】:Limit the amount of cells shown in tableView, load more cells when scroll to last cell限制tableView中显示的单元格数量,滚动到最后一个单元格时加载更多单元格
【发布时间】:2017-12-13 17:05:33
【问题描述】:

我正在尝试设置仅显示特定数量的单元格的表格视图。显示该单元格后,用户可以继续滚动以显示更多单元格。截至目前,我正在检索要在 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 函数,但出现“索引超出范围”错误。

【问题讨论】:

标签: ios json swift uitableview


【解决方案1】:

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

所以不需要限制细胞数。

我现在不知道你在代码中做了什么,但是:

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

您的应用程序可能会崩溃,因为您可能只从服务器获取了一项。

如果你真的想加载更多,那么你可以试试这个代码:

声明 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()
        }
     }
   }

【讨论】:

  • 我只想一次显示特定数量的表格视图单元格,然后用户可以决定是否要加载更多。
  • @Rahul Dasgupta 还有一个叫做 cmets 的东西。
  • @SwiftyJD 有什么按钮可以加载更多。
  • @RahulDasgupta 没有,但是一旦用户滚动到页面底部,它会加载更多。
  • @SwiftyJD 如果有效,请为我的答案投票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多