TableView
分页加载是我们在开发中最常遇到的一种需求,里面的逻辑并不复杂,但如何把他们写好,代码能够尽量多的复用起来就得下一点功夫了。
在 Objective-C 中我们可能会通过继承来抽象分页的逻辑,但是从代码工程上是能不用继承就尽量不要使用。在 swfit 中我们可以利用 protocol 来很好的抽象这部分逻辑。
首先我们需要定义分页的几个常用的属性,可用代码描述如下:
protocol PullToRefreshable: DataSourceType {
/// tableView 所用到的数据源
var datas: Pages<Item>? { get set }
/// 刷新的 view 可以是: UIScrollView/UITableView/UICollctionView
var refreshView: UIScrollView { get }
/// 刷新 API 地址,TargetType 同时封装了 `url`, `parameters`, `method`
var refreshTarget: TargetType { get }
func loadMore()
func beginRefresh()
/// 在此方法中调用 tableView.reloadData()
func reloadData()
}
利用 Extension 我们可以默认实现请求网络的方法
extension PullToRefreshable {
func refresh() {
Network.default.request(target: refreshTarget) {[weak self] (result) in
self?.refreshView.mj_header.endRefreshing()
switch result {
case let .success(response):
// Added JSON Parser
self?.reloadData()
case .error(_, _):
break
}
}
}
}
类似的其他方法都可以添加默认实现。
最后我们如果哪个 tableView 需要实现分页,我们只要去 conform 这个 protocol
即可。代码大概长这样:
extension MessageDetailViewController: PullToRefreshable {
typealias Item = MessageDetail
var refreshView: UIScrollView {
return tableView
}
var refreshTarget: TargetType {
return UserTarget.messgaeDetail(account_no: accountNo, page: 1)
}
func reloadData() {
tableView.reloadData()
}
}
是不是简单了很多呢?
在这里很多同学会不明白分页最重要的 page 参数去哪里了呢?我们可以回到上面看下是不是有个 Pages
对象,在这里我们封装了分页相关的属性,在 loadMore 方法中请求的时候只要将参数 page
赋值成 nextPage
即可。
struct Pages<T: Mappable>: Mappable {
var currentPage: Int = 1
var pageSize: Int = 20
var totalPage: Int = 0
var totalRecords: Int = 0
var items: [T] = [T]()
var nextPage: Int {
return currentPage + 1
}
init?(map: Map) {}
mutating func mapping(map: Map) {
items <- map["items"]
currentPage <- map["current_page"]
pageSize <- map["page_size"]
totalPage <- map["total_page"]
totalRecords <- map["total_records"]
}
}
这里暂时提供了一种思路,部分代码已被省略,如果有其他更好的方式,希望多多交流。
网友评论