刷新 UITableView 中的分页数据 [英] Refresh pagination data in UITableView

查看:51
本文介绍了刷新 UITableView 中的分页数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have implemented pagination in UITableView with WillDisplay method. Pagination process is working fine but if I need to reload a list on button click, then data is appending in the list. How to work around with this ?

 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 方法是

And ViewModel method is

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

推荐答案

将此方案视为可能的解决方案.

Consider this one as a possible solution.

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 中的分页数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆