Swift开发小技巧系列 - 更优雅的实现Segue

正文

我们在实际开发中偶尔会遇到一些很傻很天真的BUG,结果花了很长时间调试,最后发现这些BUG大多源于一个非常小的问题。最常见的就是在一个字符串中敲错了一两个字母。在实际开发中我们又不得不面对很多读取资源文件的操作,这些操作很多都需要直接操作资源文件名称的字符串来完成。

比如初始化Image

1
let image = UIImage(named: "checklist_not_completed_20x20_")

注:从Xcode8开始,读取image可以使用Image Literal

Perform Segue

1
self.performSegue(withIdentifier: "ShowDetail", sender: self)

这样其实有两个问题:

  1. 对于字符串Xcode IDE没有代码提示功能,重复敲这些字符串很费时间,并且当字符串稍微复杂点时,你有一定的概率敲错,增加了出BUG的概率。
  2. Xcode IDE也不会为字符串提供编译时检测,所以如果敲错,你只能等测试出现BUG,然后去查找修复,成本很高。

今天我们就来探讨下怎么优化Segue,来解决我们上面提到的问题。

1
2
3
4
5
public protocol CustomSegueProtocol {
associatedtype CustomSegueIdentifier: RawRepresentable
func performCustomSegue(_ segue: CustomSegueIdentifier, sender: Any?)
func customSegueIdentifier(forSegue segue: UIStoryboardSegue) -> CustomSegueIdentifier
}

首先定义一个协议CustomSegueProtocol,在协议里添加一个关联类型CustomSegueIdentifier,继承与RawRepresentable协议。同时声明两个方法performCustomSegue(_::)customSegueIdentifier(_:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
extension CustomSegueProtocol where Self: UIViewController,
CustomSegueIdentifier.RawValue == String {

public func performCustomSegue(_ segue: CustomSegueIdentifier, sender: Any?) {
performSegue(withIdentifier: segue.rawValue, sender: sender)
}

public func customSegueIdentifier(forSegue segue: UIStoryboardSegue) -> CustomSegueIdentifier {
guard let identifier = segue.identifier,
let customSegueIndentifier = CustomSegueIdentifier(rawValue: identifier) else {
fatalError("Cannot get custom segue indetifier for segue: \(segue.identifier ?? "").")
}

return customSegueIndentifier
}
}

CustomSegueProtocol添加默认实现,并且在添加一些约束。首先我们要求CustomSegueProtocol协议只能被UIViewController及其子类使用。其次关联类型CustomSegueIdentifierRawValueString,因为我们在storyboard里面设置Segue的identifier只能是String。具体实现内容比较简单,就是调用Apple原生处理segue的方法。

下面看看具体怎么使用?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TestCustomSegueViewController: UITableViewController, CustomSegueProtocol {
enum CustomSegueIdentifier: String {
case showNext
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performCustomSegue(.showNext, sender: self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch customSegueIdentifier(forSegue: segue) {
case .showNext:
// Configuration for next page
}
}
}

首先让你的UIViewController继承CustomSegueProtocol协议。然后把该协议的关联类型CustomSegueIdentifier定义为枚举类型,并列出所有的segue。然后在操作segue的时候调用performCustomSegue(_::)customSegueIdentifier(_:)这两个协议函数。

总结

  • 通过上面的改造,我们用新的方式来操作segue有以下一些好处:

    1. Xcode 的代码提示功能,减少了敲错字母引起BUG的概率
    2. 因为新的CustomSegueIdentifier是个强类型,Xcode能在编译时期对其进行类型检测。
    3. UIViewController统一用枚举类型定义所有的segue,方便管理维护,同时也可以充分利用枚举一些特性。
  • 具体详细代码请参考SwiftDevHints

联系方式

备注

我们在软件开发的过程中,为了提高效率,其中很重要的一环就是把反复使用到的功能或模块封装起来。因此我在GitHub上开源了一个小工具集 - SwiftDevHints,来总结自己在实际项目开发过程中封装的一些小功能。

刚刚介绍的只是其中一个小功能,想看看其它更多功能,请直接点击SwiftDevHints。如果您觉得对您有所帮助,请给一个star吧。