Swift 开发笔记 「代理」

#Program

学习自 Developing iOS Apps Using Swift


之前在一个单独文件中实现了在 iTunes 中搜索 应用名称并显示出来,代码如下:

import UIKit

class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var appsTableView: UITableView
    var tableData: NSArray = []

    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return tableData.count
    }


    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")

        var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary

        cell.textLabel.text = rowData["trackName"] as String

        // Grab the artworkUrl60 key to get an image URL for the app's thumbnail
        var urlString: NSString = rowData["artworkUrl60"] as NSString
        var imgURL: NSURL = NSURL(string: urlString)

        // Download an NSData representation of the image at the URL
        var imgData: NSData = NSData(contentsOfURL: imgURL)
        cell.imageView.image = UIImage(data: imgData)

        // Get the formatted price string for display in the subtitle
        var formattedPrice: NSString = rowData["formattedPrice"] as NSString

        cell.detailTextLabel.text = formattedPrice

        return cell
    }
    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
   return tableData.count
}

   func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath:             NSIndexPath!) -> UITableViewCell! {
       let cell: UITableViewCell = UITableViewCell(style:           UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")

       var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary

       cell.textLabel.text = rowData["trackName"] as String

       // Grab the artworkUrl60 key to get an image URL for the app's thumbnail
       var urlString: NSString = rowData["artworkUrl60"] as NSString
       var imgURL: NSURL = NSURL(string: urlString)

       // Download an NSData representation of the image at the URL
       var imgData: NSData = NSData(contentsOfURL: imgURL)
       cell.imageView.image = UIImage(data: imgData)

       // Get the formatted price string for display in the subtitle
       var formattedPrice: NSString = rowData["formattedPrice"] as NSString

       cell.detailTextLabel.text = formattedPrice

       return cell
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        api.searchItunesFor("Angry Birds")
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

但这种实现的问题在于它不符合 iOS 开发中提倡的 MVC 设计模式,所谓 MVC ,即是「Model, View, Controller」分离实现。

上面的代码将 Model 和 Control 放在了一个文件中了,下面我们将它分离开来。

首先新建一个 Swift 文件,名为 APIController.swift ,并将 searchItunesFor 函数移入 APIController.swift 文件中。

这时 Xcode 会提示三个错误,分别是:

  • searchItunesFor() is now undefined in out SearchResultsViewController.
  • self.tableData is now undefined in APIController.
  • self.appsTableView is now undefined in the APIController.

为解决第一个错误,我们需要在 SearchResultsViewController 中实例化 APIController。

在 ViewController 中声明 APIController 的实例:

var api: APIController = APIController

并将原来的调用 searchItunesFor() 变为:

api.searchItunesFor("Angry Birds")

下一步我们需要把 APIController 中产生的结果传回给 ViewController。

这里首先在 APIController 中定义一个协议如下:

protocol APIControllerProtocol {
    func didReceiveAPIResults(results: NSDictionary)
}

然后让 ViewController 继承该协议:

class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol {

在 ViewController 中声明协议要求的函数:

func didReceiveAPIResults(results: NSDictionary) {
  var resultsArr: NSArray = results["results"] as NSArray
  dispatch_async(dispatch_get_main_queue(), {
    self.tableData = resultsArr
    self.appsTableView.reloadData()
  })
}

使用协议来传递结果的方法是,先在 APIController 中声明一个代理:

var delegate: APIControllerProtocol?

然后在 ViewController 中的 viewDidLoad 函数中定义该代理:

self.api.delegate = self

最后进行数据传递,将

  dispatch_async(dispatch_get_main_queue(), {
    self.tableData = resultsArr
    self.appsTableView.reloadData()
  })

改为

self.delegate?.didReveiveAPIResults(jsonResult)

即可


END