IOS TableViewl詳解(兩種Cell註冊方式)

學習iOS第二週,學習到了比較重要的組件TableView,照着書上敲,沒有實現效果。在同事的幫助下,有了比較清晰的理解,記錄在此。

我使用的完全是xib的方式。我們先按照這種方式來梳理出Demo

先看下項目結構目錄

先從最簡單的model開始看起,可以理解爲javabean

//
//  News.swift
//  HelloIOS
//
//  Created by zxg on 2018/9/27.
//  Copyright © 2018年 zxg. All rights reserved.
//

import UIKit

class News: NSObject {
    
    var title:String = "" //新聞標題
    var desc:String = "" //新聞描述
    
    init(title:String,desc:String){
        self.title = title
        self.desc = desc
    }


}

接下來是cell

在NewsViewCell.xib中,引入兩個lib,並關聯到NewsViewCell.swift中,比較簡單,直接上截圖:
 

我們拖拽了兩個label,一個用於顯示title,一個用於顯示描述

接下來是重要的Controller,有兩種方案,第一種自己編寫的Controller繼承自UIViewController,自己去實現UITableView的兩個委託,並手動在xib文件中拖拽tableview並關聯。第二種是自己編寫的Controller直接繼承系統提供的UITableViewController,這種方案比較省事,一來,不用手動實現委託,二來xib中會自帶tableview,不需要再手動關聯。這裏我們先放下系統提供的UITableViewController

import Foundation
import UIKit
import _SwiftUIKitOverlayShims

//
//  UITableViewController.h
//  UIKit
//
//  Copyright (c) 2008-2017 Apple Inc. All rights reserved.
//

// Creates a table view with the correct dimensions and autoresizing, setting the datasource and delegate to self.
// In -viewWillAppear:, it reloads the table's data if it's empty. Otherwise, it deselects all rows (with or without animation) if clearsSelectionOnViewWillAppear is YES.
// In -viewDidAppear:, it flashes the table's scroll indicators.
// Implements -setEditing:animated: to toggle the editing state of the table.

@available(iOS 2.0, *)
open class UITableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {

    
    public init(style: UITableViewStyle)

    public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)

    public init?(coder aDecoder: NSCoder)

    
    open var tableView: UITableView!

    @available(iOS 3.2, *)
    open var clearsSelectionOnViewWillAppear: Bool // defaults to YES. If YES, any selection is cleared in viewWillAppear:

    
    @available(iOS 6.0, *)
    open var refreshControl: UIRefreshControl?
}

可以看到繼承自UIViewController並實現委託,同時存在變量tableView。我們可以直接使用

接下來,放下我的Controller的代碼,很多關鍵點都在註釋中說明了

//
//  NewsViewController.swift
//  HelloIOS
//
//  Created by zxg on 2018/9/26.
//  Copyright © 2018年 zxg. All rights reserved.
//

import UIKit

class NewsViewController: UITableViewController {
    
    //模擬數據源
    let newsItem = [News(title: "吳秀波出軌", desc: "吳秀波圈養小妾"),News(title: "中美貿易升級", desc: "美提升2000億關稅"),News(title: "海底撈上市", desc: "創始人張勇暴富"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨"),News(title: "全國喜迎十一長假", desc: "國慶黃金週即將來臨")]
    let cellIdentifier = "NewsCell"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //將TableView背景橫線去掉
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
        
        //兩種register方式:
        //通過UINib註冊,適用於xib方式,本例中,cell採用的是xib方式而非純代碼。
        let nib = UINib.init(nibName: "NewsViewCell", bundle: nil)
        tableView.register(nib, forCellReuseIdentifier: cellIdentifier)
        
        /*通過class註冊,適用於純代碼方式,需要在cell文件中重寫init(style: UITableViewCellStyle, reuseIdentifier: String?)
          在其中初始化view
        */
        //tableView.register(NewsViewCell.self, forCellReuseIdentifier: cellIdentifier)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source
    //UITableViewDataSource委託協議:返回小節的數量
    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    //UITableViewDataSource委託協議:返回每個小節的item數量,section爲小節Index
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return newsItem.count
    }

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

        /*使用dequeueReusableCell(withIdentifier: cellIdentifier)方法獲取cell不需要通過register註冊,但是要判斷cell是否爲空,爲空則new cell
        var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? NewsViewCell

        if(cell == nil){
            cell = NewsViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellIdentifier)
        } */

        /*使用dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)獲取cell,其實就使用了tableview的緩存機制,當取到cell爲空時
          系統會幫忙創建register的cell,所以就不需要我們手動判空並實例化cell。所以必須register
        */
        // Configure the cell...
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? NewsViewCell
        let row = indexPath.row
        let news:News = newsItem[row]
        cell?.tvNewsTitle?.text = news.title
        cell?.tvNewsDesc?.text = news.desc
        return cell!
    
    }
    //返回每個cell的高度
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100.0
    }
    
}

補一張NewsViewCell.swift的代碼,其中也包含了一些註釋:

//
//  NewsViewCell.swift
//  HelloIOS
//
//  Created by zxg on 2018/9/26.
//  Copyright © 2018年 zxg. All rights reserved.
//

import UIKit

class NewsViewCell: UITableViewCell {

    @IBOutlet weak var tvNewsTitle: UILabel!
    @IBOutlet weak var tvNewsDesc: UILabel!
    //使用xib方式創建cell,在dequeueReusableCell()時會調用到該方法
    //本例中使用的是xib方式
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    //使用純代碼方式創建cell,在dequeueReusableCell()時會調用到該方法
    //需要在該方法中創建view
//    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        //例如創建如下view:
//        super.init(style: style, reuseIdentifier: reuseIdentifier)
//        self.iconImageView=UIImageView()
//        self.contentView.addSubview(self.iconImageView!)
//        self.TitleLabel=UILabel()
//        self.contentView.addSubview(self.TitleLabel!)
//        setUpviews()
//    }
    
    
}

關於純代碼創建cell,這篇文章代碼可看:https://www.cnblogs.com/small-Sun/p/5667764.html

關於UITableView複用機制理解:https://blog.csdn.net/wuzesong/article/details/52225487

總結:

1、dequeueReuseableCellWithIdentifier:與dequeueReuseableCellWithIdentifier:forIndexPath:的區別:
前者不必向tableView註冊cell的Identifier,但需要判斷獲取的cell是否爲nil;
後者則必須向table註冊cell,可省略判斷獲取的cell是否爲空,因爲無可複用cell時runtime將使用註冊時提供的資源去新建一個cell並返回。
2、自定義cell時,記得將其他內容加到self.contentView 上,而不是直接添加到 cell 本身上
總結:
1.自定義cell時,
若使用nib,使用 registerNib: 註冊,dequeue時會調用 cell 的 -(void)awakeFromNib
不使用nib,使用 registerClass: 註冊, dequeue時會調用 cell 的 - (id)initWithStyle:withReuseableCellIdentifier:
2.需不需要註冊?
使用dequeueReuseableCellWithIdentifier:可不註冊,但是必須對獲取回來的cell進行判斷是否爲空,若空則手動創建新的cell;
使用dequeueReuseableCellWithIdentifier:forIndexPath:必須註冊,但返回的cell可省略空值判斷的步驟。

寫在最後:

本文介紹內容比較淺顯,沒有深究例如tableView緩存機制,xib講解等。是因爲我還沒深入學習到。會在後邊的文章接受

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章