iOS 中使用 protocol 來重構分頁載入

racechao發表於2018-06-05

iOS 中使用 protocol 來重構分頁載入

TableView 分頁載入是我們在開發中最常遇到的一種需求,裡面的邏輯並不複雜,但如何把他們寫好,程式碼能夠儘量多的複用起來就得下一點功夫了。 在 Objective-C 中我們可能會通過繼承來抽象分頁的邏輯,但是從程式碼工程上是能不用繼承就儘量不要使用。在 swfit 中我們可以利用 protocol 來很好的抽象這部分邏輯。 首先我們需要定義分頁的幾個常用的屬性,可用程式碼描述如下:

protocol PullToRefreshable: DataSourceType {

    /// tableView 所用到的資料來源
    var datas: Pages<Item>? { get set }
    
    /// 重新整理的 view 可以是: UIScrollView/UITableView/UICollctionView
    var refreshView: UIScrollView { get }
    
    /// 請求 `target`: TargetType 同時封裝了 `url`, `parameters`, `method`
    var refreshTarget: TargetType { get }
    
    func refresh()
    
    func loadMore()
    
    /// 在此方法中呼叫 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"]
    }
}
複製程式碼

這裡暫時提供了一種思路,部分程式碼已被省略,如果有其他更好的方式,希望多多交流。

相關文章