如何使用委托模式

打开 ViewController.swift 文件,添加如下私有变量:

1. private var allAlbums = [Album]()
2. private var currentAlbumData : (titles:[String], values:[String])?
3. private var currentAlbumIndex = 0

在 viewDidLoad 里面加入如下内容:

1. override func viewDidLoad() {
2. super.viewDidLoad()
3. //1
4. self.navigationController?.navigationBar.translucent = false
5. currentAlbumIndex = 0

7. //2
8. allAlbums = LibraryAPI.sharedInstance.getAlbums()

10. // 3
11. // the uitableview that presents the album data
12. dataTable.delegate = self
13. dataTable.dataSource = self
14. dataTable.backgroundView = nil
15. view.addSubview(dataTable!)
16. }

对上面三个部分进行拆解:

  1. 关闭导航栏的透明效果
  2. 通过 API 获取所有的专辑数据,记住,我们使用外观模式之后,应该从 LibraryAPI 获取数据,而不是 PersistencyManager 。
  3. 你可以在这里设置你的 UITablweView ,在这里声明了 UITableView 的 delegate 是当前的 ViewController 。事实上你用了 XIB 或者 StoryBoard ,可以直接在可视化的页面里拖拽完成。

接下来添加一个新的方法用来更方便的获取数据:

1. func showDataForAlbum(albumIndex: Int) {
2. // defensive code: make sure the requested index is lower than the amount of albums
3. if (albumIndex < allAlbums.count && albumIndex > -1) {
4. //fetch the album
5. let album = allAlbums[albumIndex]
6. // save the albums data to present it later in the tableview
7. currentAlbumData = album.ae_tableRepresentation()
8. } else {
9. currentAlbumData = nil
10. }
11. // we have the data we need, let's refresh our tableview
12. dataTable!.reloadData()
13. }

showDataForAlbum() 这个方法获取最新的专辑数据,当你想要展示新数据的时候,你需要调用 reloadData() 这个方法,这样 UITableView 就会向委托请求数据,比如有多少个 section 有多少个 row 之类的。

在 viewDidLoad 里面调用上面的方法:

1. self.showDataForAlbum(currentAlbumIndex)

这样应用一启动就会去加载当前的专辑数据。因为 currentAlbumIndex 的默认值是 0 ,所以一开始会默认显示第一章专辑的信息。

接下来我们该去完善 DataSource 的协议方法了。你可以直接把委托方法写在类里面,当然如果你想让你的代码看起来更整洁一点,则可以放在扩展里。

在文件底部添加如下方法,注意一定要放在类定义的大括号外面,因为这两个家伙不是类定义的一部分,它们是扩展:

1. extension ViewController: UITableViewDataSource {
2. }

4. extension ViewController: UITableViewDelegate {
5. }

上面就是实现委托的方法 - 你可以把协议想象成是与委托之间的约定,只要你实现了约定的方法,就算是实现了委托。在我们的代码中, ViewController 需要遵守 UITableViewDataSource 和 UITableViewDelegate 的协议。这样 UITableView 才能确保必要的委托方法都已经实现了。

在 UITableViewDataSource 对应的那个扩展里加上如下方法:

1. func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2. if let albumData = currentAlbumData {
3. return albumData.titles.count
4. } else {
5. return 0
6. }
7. }

9. func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
10. let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
11. if let albumData = currentAlbumData {
12. cell.textLabel?.text = albumData.titles[indexPath.row]
13. if let detailTextLabel = cell.detailTextLabel {
14. detailTextLabel.text = albumData.values[indexPath.row]
15. }
16. }
17. return cell
18. }

tableView(_![:numberOfRowsInSection:](https://www.emoji-cheat-sheet.com/graphics/emojis/numberOfRowsInSection.png ":numberOfRowsInSection:")) 返回需要展示的行数,和存储的数据中的 title 的数目相同。

tableView(_![:cellForRowAtIndexPath:](https://www.emoji-cheat-sheet.com/graphics/emojis/cellForRowAtIndexPath.png ":cellForRowAtIndexPath:")) 创建并且返回了一个单元格,上面有标题和对应的值。

注意:你可以把这些方法直接加在类声明里面,也可以放在扩展里,编译器不会去管数据源到底在哪里,只要能找到对应的方法就可以了。而我们之所以这样做,是为了方便其他人阅读。

此时再构建项目,你可以看到如下内容:

如何使用委托模式 - 图3

是的,显示成功啦!

我们的原计划是在上面的空白处放一个可以横滑浏览专辑的视图。其实仔细想想,这个控件是可以应用在其他地方的,我们不妨把它做成一个可复用的视图。

为了让这个视图可以复用,显示内容的工作都只能交给另一个对象来完成:它的委托。这个横滑页面应该声明一些方法让它的委托去实现,就像是 UITableView 的 UITableViewDelegate 一样。我们将会在下一个设计模式中实现这个功能。

完成到这一步的Demo: