在优雅的使用UITableView(OC 上)中,已经给你们分享了怎么使用UITableView
,优雅的构建一个页面。git
再回忆一下这张图 github
其中关键的点其实就是Row,若是咱们把Row作好了,其实大功基本告成。编程
看当作果:swift
Swift版的是否是更优雅了些?数组
struct NoneItem {}
protocol Updatable: class {
associatedtype ViewData
func update(viewData: ViewData)
}
extension Updatable {
func update(viewData: NoneItem) {}
}
protocol RowType {
var tag: RowTag { get }
var reuseIdentifier: String { get }
var cellClass: AnyClass { get }
func update(cell: UITableViewCell)
func cell<C: UITableViewCell>() -> C
func cellItem<M>() -> M
}
class Row<Cell> where Cell: Updatable, Cell: UITableViewCell {
let tag: RowTag
let viewData: Cell.ViewData
let reuseIdentifier = "\(Cell.classForCoder())"
let cellClass: AnyClass = Cell.self
init(viewData: Cell.ViewData, tag: RowTag = .none) {
self.viewData = viewData
self.tag = tag
}
func cell<C: UITableViewCell>() -> C {
guard let cell = _cell as? C else {
fatalError("cell 类型错误")
}
return cell
}
func cellItem<M>() -> M {
guard let cellItem = viewData as? M else {
fatalError("cellItem 类型错误")
}
return cellItem
}
private var _cell: Cell?
func update(cell: UITableViewCell) {
if let cell = cell as? Cell {
self._cell = cell
cell.update(viewData: viewData)
}
}
}
extension Row: RowType {}
public class RowTags {
fileprivate init() {}
}
public class RowTag: RowTags {
public let _key: String
public init(_ key: String) {
self._key = key
super.init()
}
}
extension RowTag: Hashable {
public static func ==(lhs: RowTag, rhs: RowTag) -> Bool {
return lhs.hashValue == rhs.hashValue
}
public var hashValue: Int {
return _key.hashValue
}
}
extension RowTags {
static let none = RowTag("")
}
复制代码
以上代码,对比OC实现主要有三点不一样:app
不知道你对RowType这个协议的存在是否感到疑惑,假如没有它行不行?函数
若是没有RowType这个协议,这两个row应该放在什么类型的数组里呢?post
你打算用Any?那你的代码里确定会出现一堆as? 的代码,显然与咱们谈到的优雅背道而驰。ui
是否是典型的面相协议编程?spa
若是没有怎么接触过Swift的同窗,或者不太了解泛型的同窗,看到上面的语法,确定是一脸的懵逼。
在这里简单给不太了解的同窗普及一下。
泛型,泛型,从字面理解就是普遍的类型嘛,就是各类姿式都知足,可是他和Any有什么不一样呢?
咱们先来看这么一个需求,我想写一个max函数,他要使用各类类型,若是没有接触过泛型的同窗写出来的函数应该是这样(请只看方法定义)
func anyMax(_ x: Any, _ y: Any) -> Any {
....
}
复制代码
若是对于OC那样指针操做的语言这彷佛没有问题,可是这对于Swift这样的强类型语言就颇有问题了。
为何?
假如我比较两个Int类型的数字,返回的是Any,这显然不是我想要的
let n = 1
let m = 2
// result 的类型会为Any
let result = anyMax(n, m)
复制代码
再看泛型版本
func genericMax<T>(_ x: T, _ y: T) -> T {
....
}
复制代码
let n = 1
let m = 2
// result 的类型会为Int
let result = genericMax(n, m)
复制代码
由于Swift有类型推断,因此咱们在输入值比较时就知道了咱们的result类型为Int
泛型
Any会形成类型丢失
where关键字表示约束条件,T必须为遵循了协议Comparable的类型
再看一遍这张图
这有三组样式的UITableView
其实List和Detail维护的东西是同样的,就是那个RowContainer。
核心代码
在此OC和Swift的优雅使用UITabelView都已经和你们介绍完毕了。
下一节会和你们分享一下在我开发中,对Detail界面的运用和List界面的运用,以及怎么用泛型去对Detail模型和List模型的解析。
在上一节中,有不少同窗给我推荐了一些表单的库,其实我本身也知道有不少优秀的表单库,列如Eureka、XLForm等等。
那么,我为何还要本身造轮子?
两个主要的缘由:
在上一节中看到评论中主要有两个问题:
func buttonAction(_ sender: UIButton) {
(self.viewController as? ButtonCellActionable)?.buttonAction(sender, cell: self)
}
复制代码
self.viewController
为nil,为何事件还能相应?其实为nil,在我开发时,我是知道的,但我错误的理解为,系统会在运行时再去拿那个target。
为nil的缘由实际上是button尚未添加在superView上,响应链还找不到他的UIViewContoller。
那么既然,target没有被系统持有,那么,为何事件还能相应?
这就是UIKit中的定义,就是target为nil的时候,会走相应链 ,而我以前的实现,又刚好在VC中实现了,因此方法会被调用。
关于addTarget这个方法的更多事情,请看这里