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