UITableView 的数据显示主要牵扯到的就是一个数据源方法的使用。
基本思路是:
- 数据源的设置
- 数据源方法的实现
- tableView 对数据源的三次询问
3.1 tableView 有多少组
3.2 tableView 每组有多少行
3.3 tableView 每行显示什么内容
//******************* 这三个方法是 tableView 显示数据的基本方法,实现这三个方法就可以显示 tableView 的内容 ************************
@available(iOS 2.0, *) // iOS 2.O 开始使用
// tableView 有多少行
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// 行显示的时候,通过设置 cell 的重用标识符,和调用 dequeueReusableCellWithIdentifier 方法来确认是否有可重用的 cell,尝试去重用 cell,
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
@available(iOS 2.0, *)
// 每一行 cell 显示什么内容
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
@available(iOS 2.0, *)
// tableView 有多少组 ( 这个方法是可选的 默认的实现返回时 1 ,不实现这个数据源方法,tableView 就显示一组数据)
optional public func numberOfSectionsInTableView(tableView: UITableView) -> Int // Default is 1 if not implemented
1、tableView 数据显示的基本设置
简单数据展示的实例
只是展示了一个单行的文本数据
//
// ViewController.swift
// UITableViewTest
//
// Created by 肖卓鸿 on 16/6/2.
// Copyright © 2016年 肖卓鸿. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
var tableView: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView()
// 1. 设置数据源代理
tableView?.dataSource = self
view.addSubview(tableView!)
}
// 2. 这里进行 tableView 的 frame 设置主要是屏幕的适配
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView?.frame = view.frame
}
}
// 实现数据源
// MARK: - UITableViewDataSource
/*
使用扩展来实现数据源,这样会使代码结构看起来更加清晰。
*/
extension ViewController : UITableViewDataSource {
// 3.1 tableView 有几组
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
// 3.2 tableView 每组有几行
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
// 3.3 tableView 每行显示什么内容
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 创建 cell (cell 没有使用重用, 此处只是为了展示基本使用)
let cell = UITableViewCell()
// cell 文本数据的显示内容设置
cell.textLabel?.text = "\(indexPath.section)组" + "-" + "\(indexPath.row)行"
return cell
}
}
效果图:
数据源方法调用的追踪
在三个数据源方法中添加
print(#function)
numberOfSectionsInTableView
tableView(_:numberOfRowsInSection:)
tableView(_:numberOfRowsInSection:)
numberOfSectionsInTableView
tableView(_:numberOfRowsInSection:)
tableView(_:numberOfRowsInSection:)
numberOfSectionsInTableView
tableView(_:numberOfRowsInSection:)
tableView(_:numberOfRowsInSection:)
numberOfSectionsInTableView
tableView(_:numberOfRowsInSection:)
tableView(_:numberOfRowsInSection:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
tableView(_:cellForRowAtIndexPath:)
- 方法的调用顺序是
numberOfSectionsInTableView
tableView(:numberOfRowsInSection:)
tableView(:cellForRowAtIndexPath:)
2、cell 视图的重用
为了提高 tableView 的性能,我们对 cell 进行重用。
使用重用之后,第一次加载 tableView 的时候就只会创建界面可以显示的几个 cell,当滚动 tableView 的时候,会从缓存池中获取 cell 不会创建 cell 。当 cell 消失的时候将 cell 放入缓存池中。
在上面的数据源方法中返回 10000
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100000
}
这样就可以感觉到明显的卡顿。而且内存也会暴涨。(在 cell 上设置图片后效果会比较明显)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 创建 cell (cell 没有使用重用, 此处只是为了展示基本使用)
let cell = UITableViewCell()
print(#function)
return cell
}
会打印 100000 次
使用重用后,界面可以显示几个 cell 就打印几次
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 老程序员会这么写 cell 的重用
var cell = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil {
cell = UITableViewCell(style: .Default, reuseIdentifier: "cell")
}
print(#function)
return cell!
}
相比之下性能会高很多
上面是老式的 cell 的重用写法
cell 重用的使用步骤
- 注册 cell
- 数据源方法中获取 cell
- 设置 cell 的数据后 在数据源方法中返回 cell
cell 的注册:
// cell 的 nib 方式注册,
public func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)
// cell 的 class 方式注册
public func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
// header 和 footer nib 方式注册
public func registerNib(nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String)
// header 和 footer class 方式注册
public func registerClass(aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String)
// 注册代码
tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: UITableViewCell.identifier)
tableView.registerNib(UITableViewCell.nib, forCellReuseIdentifier: UITableViewCell.identifier)
// UITableViewCell.nib 和 UITableViewCell.identifier 的说明
import UIKit
extension UITableViewCell {
/*!
cell 重用标识符 (标识符默认就是 class 的字符串)
*/
class var identifier:String {
return "\(self.classForCoder())"
}
/*!
cell 的 nib 文件
*/
class var nib:UINib {
return UINib(nibName: "\(self.classForCoder())", bundle: nil)
}
}
使用 UITableViewCell.nib 和 UITableViewCell.identifier 这种方式可以避免直接写字符串容易写错的麻烦
注意点: 使用 nib 方式的时候,xib 的文件名称和 视图类的类名一定要相同。
缓存池中 cell 的获取
public func dequeueReusableCellWithIdentifier(identifier: String) -> UITableViewCell? // Used by the delegate to acquire an already allocated cell, in lieu of allocating a new one.
// 使用这个方法 cell 必须是注册的(这是和上面方法的最大区别)
public func dequeueReusableCellWithIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath) -> UITableViewCell
// cell 从缓存池中获取的代码
// 不进行注册,就使用旧的写法就可以了
let cell = tableView.dequeueReusableCellWithIdentifier(UITableViewCell.identifier)
// 使用这个方法 cell 必须提前注册
let cell = tableView.dequeueReusableCellWithIdentifier(UITableViewCell.identifier, forIndexPath: indexPath)
// cell 数据的设置 和 cell 返回
cell?.textLabel?.text = "hello world"
return cell!