刷新 UITableView 中的分页数据

Posted

技术标签:

【中文标题】刷新 UITableView 中的分页数据【英文标题】:Refresh pagination data in UITableView 【发布时间】:2020-02-10 12:36:15 【问题描述】:

我已经用 WillDisplay 方法在 UITableView 中实现了分页。分页过程工作正常,但如果我需要在单击按钮时重新加载列表,则数据会附加到列表中。如何解决这个问题?

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
     if (indexPath.row + 1 == playlistViewModel.numberOfRowsInSection()) 
         if playlistViewModel.isReload != false 
             pageIncrement += 1
             playlistViewModel.playListingApi(enterView: false, page: pageIncrement)
         
     
 

 override func viewDidLoad() 
     super.viewDidLoad()
     // Do any additional setup after loading the view.
     pageIncrement = 1
     playlistViewModel.playListingApi(enterView: true, page: pageIncrement)
 


 playlistViewModel.hitNextApiClosure =  [weak self] () in
     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) 
         self?.playlistViewModel.isReload = false
         self?.playlistViewModel.playlistArray?.removeAll()
         self?.playlistTableView.reloadData()
         self?.pageIncrement = 1
         self?.playlistViewModel.playListingApi(enterView: true, page: self?.pageIncrement ?? 1)
     
 

ViewModel 方法是

 func playListingApi(enterView: Bool, page: Int) 
     self.isLoading = true
     if (enterView)
         playlistArray?.removeAll()
         isReload = false
     
     playlistService.getPlayList(page: "\(page)", limit: "20")  (result) in
         self.isLoading = false
         switch result 
         case .success(let data):

             self.playlist = data as? Playlist
             guard let data = self.playlist?.data?.blocks else 
                 self.errorMessage = AlertMessage.somethingWentWrong
                 return
             
             for playlistData in data 
                 self.playlistArray?.append(playlistData)
                 self.isReload = true
             
             if (data.count == 0)
                 self.isReload = false 
             
             self.reloadTableBool = true
         case .error(let message):
             self.isReload = false
             self.errorMessage = message
         
     
 

【问题讨论】:

点击右键重新加载所有数据? 是的,正确的@Yogesh 【参考方案1】:

当您重新加载 tableView 设置 page = 1 时,清空 tableView 数据源并重新加载 tableView。最后hitAPI 获取新数据集。

 page = 1
 mTblDataSource.removeAll()
 mTableView.reloadData()
 hitAPI()

【讨论】:

@vasud- 我正在做同样的事情,你可以看到上面共享的代码。事情是会显示方法正在制造问题并使数组加倍【参考方案2】:

将此视为一种可能的解决方案。

public class Pageable<T> 

    public enum ObjectState 
        case loading
        case loaded
    

    public private (set) var page: Int = 0

    private var items: [T] = [T]()
    private var state: ObjectState = .loading
    private let itemsPerPage: Int
    private var itemsReloaded: (() -> ())

    public init(itemsPerPage: Int, items: [T] = [], itemsReloaded: @escaping (() -> ())) 
        self.items = items
        self.itemsPerPage = itemsPerPage
        self.itemsReloaded = itemsReloaded
    

    public var itemsCount: Int 
        switch state 
        case .loaded:
            return items.count
        case .loading:
            return items.count + 1 // should be displaying cell with loading indicator
        
    

    public var isLoaded: Bool 
        return state == .loaded
    

    public var isLoading: Bool 
        return state == .loading
    

    public func append(contentsOf items: [T]) 
        state = items.count < itemsPerPage ? .loaded : .loading
        self.items.append(contentsOf: items)
        itemsReloaded()
    

    public func incrementPage() 
        page += 1
    

    public func reset() 
        page = 0
        state = .loading
        items = []
    

    public func itemFor(_ index: Int) -> T? 
        return items.indices.contains(index) ? items[index] : nil
    


struct Property 

protocol SearchItemsDisplayLogic: class 
    func reloadItemsViews()


protocol SearchItemsInteraction 
    func loadMore(page: Int)


// MARK: View Related with UITableView example
lazy var refreshControl: UIRefreshControl = 
    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(pullToRefresh(_:)), for: UIControl.Event.valueChanged)

    return refreshControl
()

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return presenter.itemsCount


func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
    presenter.viewWillDisplayCellAt(indexPath.row)


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        if presenter.isLoadingCellNeeded(indexPath.row) 
            return tableView.dequeueReusableCell(withIdentifier: "\(LoadingTableViewCell.self)", for: indexPath)
        

        let cell = tableView.dequeueReusableCell(withIdentifier: "\(PropertyTableViewCell.self)", for: indexPath) as? PropertyTableViewCell

        presenter.populate(cell: cell, indexPath: indexPath)

        return cell ?? UITableViewCell(style: .default, reuseIdentifier: "\(UITableViewCell.self)")
    


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    let property = presenter.property(indexPath.row) else 
        return
    


protocol SearchItemsPresentation 

    // MARK: Pagination logic
    var itemsCount: Int  get 

    // From the view.
    func isLoadingCellNeeded(_ item: Int) -> Bool
    func viewWillDisplayCellAt(_ item: Int)
    func pullToRefresh()
    func property(_ item: Int) -> Property?

    // From the interactor.
    func presentItems(items: [Property])


// MARK: - Presenter
class SearchItemsPresenter: SearchItemsPresentation 

    weak var propertyDisplay: SearchItemsDisplayLogic?
    lazy var interactor: SearchItemsInteraction? = 
        return SearchItemsInteractor(presenter: self)
    ()

    var itemsCount: Int 
        return pageable.itemsCount
    

    private var pageable: Pageable<Property>!

    init(viewController: SearchItemsDisplayLogic) 
        self.propertyDisplay = viewController

        pageable = Pageable(itemsPerPage: 15, itemsReloaded: 
            self.propertyDisplay?.reloadItemsViews()
        )
    

    // TODO: presenter should not have UIKit!
    func populate(cell: CellProtocol?, indexPath: IndexPath) 

        guard let cell = cell else  return 

        // populate
    


extension SearchItemsPresenter 
    func property(_ index: Int) -> Property? 
        return pageable.itemFor(index)
    


// MARK: Pageable
extension SearchItemsPresenter 

    /// if it's loading show loading cell in the view.
    func isLoadingCellNeeded(_ item: Int) -> Bool 
        let isViewAtTheBottom = item == itemsCount - 1

        return isViewAtTheBottom && pageable.isLoading
    

    /// Called in `willDisplay` methods of the view.
    func viewWillDisplayCellAt(_ item: Int) 
        let isViewAtTheBottom = item == itemsCount - 1

        if isViewAtTheBottom && pageable.isLoading 
            interactor?.loadMore(page: pageable.page)
            pageable.incrementPage()
        
    

    func pullToRefresh() 
        pageable.reset()
        interactor?.loadMore(page: pageable.page)
        pageable.incrementPage()
    

    func presentItems(items: [Property]) 
        pageable.append(contentsOf: items)
    


// MARK: - Interactor
class SearchItemsInteractor: SearchItemsInteraction 

    private var presenter: SearchItemsPresentation

    init(presenter: SearchItemsPresentation) 
        self.presenter = presenter
    

    func loadMore(page: Int) 
        DispatchQueue.global(qos: .background).async 
            sleep(1)
            DispatchQueue.main.async 
                // TODO: return some data
                self.presenter.presentItems(items: [])
            
        
    

【讨论】:

以上是关于刷新 UITableView 中的分页数据的主要内容,如果未能解决你的问题,请参考以下文章

采用AJAX + history api做无刷新页面的分页

asp.net 带有gridview的分页无刷新,急求,使用ajax

FMDB 和 UITableView

J2EE简单的分页器

ios UITableView刷新TableCell问题

dolphindb 中的分页数据