刷新 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 中的分页数据的主要内容,如果未能解决你的问题,请参考以下文章