在優雅的使用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實現主要有三點不一樣:markdown
不知道你對RowType這個協議的存在是否感到疑惑,假如沒有它行不行?app
若是沒有RowType這個協議,這兩個row應該放在什麼類型的數組裏呢?函數
你打算用Any?那你的代碼裏確定會出現一堆as? 的代碼,顯然與咱們談到的優雅背道而馳。oop
是否是典型的面相協議編程?post
若是沒有怎麼接觸過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這個方法的更多事情,請看這裏