转载

优雅的使用UITableView(Swift 中)

优雅的使用UITableView(OC 上)中,已经给大家分享了怎么使用UITableView,优雅的构建一个页面。

在这一节,主要和大家聊一聊这两点:

  1. 怎么把优雅的使用UITableView(OC 上)的思路搬到Swift

  2. 泛型Any的区别

  3. 在Swift中优雅的使用UITableView构建List页面

怎么把优雅的使用UITableView(OC 上)的思路搬到Swift

再回忆一下这张图

优雅的使用UITableView(Swift 中)

其中关键的点其实就是Row,如果我们把Row做好了,其实大功基本告成。

看看成果:

优雅的使用UITableView(Swift 中)

Swift版的是不是更优雅了些?

Row的实现

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
    func cellItem() -> M
}
class Row 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 {
        guard let cell = _cell as? C else {
            fatalError("cell 类型错误")
        }
        return cell
    }
    
    func cellItem() -> 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实现主要有三点不同:

  • CellClass从参数变为泛型

  • RowType的存在

  • RowTags(主要用来取Row,代替IndexPath)

不知道你对RowType这个协议的存在是否感到疑惑,假如没有它行不行?

优雅的使用UITableView(Swift 中)

如果没有RowType这个协议,这两个row应该放在什么类型的数组里呢?

你打算用Any?那你的代码里肯定会出现一堆as? 的代码,显然与我们谈到的优雅背道而驰。

其实RowType的存在就是这些元素的抽象,让我们知道这些元素的共同属性。

是不是典型的面相协议编程?

泛型和Any的区别

如果没有怎么接触过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(_ x: T, _ y: T) -> T {
    ....
}
let n = 1
let m = 2
// result 的类型会为Int
let result = genericMax(n, m)

因为Swift有类型推断,所以我们在输入值比较时就知道了我们的result类型为Int

那么我们可以总结出泛型和Any的最大区别就是:

  • 泛型

    输入与输出结果类型一致

    延迟类型的确定

  • Any会造成类型丢失

Swift中max函数的实现

优雅的使用UITableView(Swift 中)

where关键字表示约束条件,T必须为遵循了协议Comparable的类型

在Swift中优雅的使用UITableView构建List页面

再看一遍这张图

优雅的使用UITableView(Swift 中)

这有三组样式的UITableView

优雅的使用UITableView(Swift 中)

其实ListDetail维护的东西是一样的,就是那个RowContainer。

核心代码

优雅的使用UITableView(Swift 中)

尾巴

在此OC和Swift的优雅使用UITabelView都已经和大家介绍完毕了。

下一节会和大家分享一下在我开发中,对Detail界面的运用和List界面的运用,以及怎么用泛型去对Detail模型和List模型的解析。

在上一节中,有很多同学给我推荐了一些表单的库,其实我自己也知道有很多优秀的表单库,列如Eureka、XLForm等等。

那么,我为什么还要自己造轮子?

两个主要的原因:

  • 那些库都太重了

  • 都只支持Detail,List界面没有办法兼容

其实我也只是站在了大佬的肩上而已

在上一节中看到评论中主要有两个问题:

我用了响应链的传值方式,怎么传递参数?

func buttonAction(_ sender: UIButton) {
         (self.viewController as? ButtonCellActionable)?.buttonAction(sender, cell: self)
     }
  • 在执行懒加载UIbutton时,self.viewController为nil,为什么事件还能相应?

优雅的使用UITableView(Swift 中)

其实为nil,在我开发时,我是知道的,但我错误的理解为,系统会在运行时再去拿那个target。

为nil的原因其实是button还没有添加在superView上,响应链还找不到他的UIViewContoller。

那么既然,target没有被系统持有,那么,为什么事件还能相应?

优雅的使用UITableView(Swift 中)

这就是UIKit中的定义,就是target为nil的时候,会走相应链 ,而我之前的实现,又恰好在VC中实现了,所以方法会被调用。

关于addTarget这个方法的更多事情,请看这里

Demo

表单库:

作者:xiAo-ju
链接:https://juejin.im/post/5a64509cf265da3e36415bd3

正文到此结束
Loading...