学习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讲解等。是因为我还没深入学习到。会在后边的文章接受