Delegation Pattern

Delegation

The other Decorator design pattern, Delegation, is a mechanism in which one object acts on behalf of, or in coordination with, another object. For example, when you use a UITableView, one of the methods you must implement is tableView(_:numberOfRowsInSection:).
You can’t expect the UITableView to know how many rows you want to have in each section, as this is application-specific. Therefore, the task of calculating the amount of rows in each section is passed on to the UITableView delegate. This allows the UITableView class to be independent of the data it displays.
Here’s a pseudo-explanation of what’s going on when you create a new UITableView:
delegate
The UITableView object does its job of displaying a table view. However, eventually it will need some information that it doesn’t have. Then, it turns to its delegates and sends a message asking for additional information. In Objective-C’s implementation of the delegate pattern, a class can declare optional and required methods through a protocol. You’ll cover protocols a bit later in this tutorial.
It might seem easier to just subclass an object and override the necessary methods, but consider that you can only subclass based on a single class. If you want an object to be the delegate of two or more other objects, you won’t be able to achieve this by subclassing.
Note: This is an important pattern. Apple uses this approach in most of the UIKit classes: UITableViewUITextViewUITextFieldUIWebViewUIAlertUIActionSheetUICollectionViewUIPickerViewUIGestureRecognizerUIScrollView. The list goes on and on.

How to Use the Delegate Pattern

Open up ViewController.swift and add these private properties to the class:
private var allAlbums = [Album]()
private var currentAlbumData : (titles:[String], values:[String])?
private var currentAlbumIndex = 0
Next, replace viewDidLoad with this code:
override func viewDidLoad() {
  super.viewDidLoad()
  //1
  self.navigationController?.navigationBar.translucent = false
  currentAlbumIndex = 0
 
  //2
  allAlbums = LibraryAPI.sharedInstance.getAlbums()
 
  // 3
  // the uitableview that presents the album data
  dataTable.delegate = self
  dataTable.dataSource = self
  dataTable.backgroundView = nil
  view.addSubview(dataTable!)  
}
Here’s a breakdown of the above code:
  1. Turn off translucency on the navigation bar.
  2. Get a list of all the albums via the API. Remember, the plan is to use the facade of LibraryAPI rather than PersistencyManager directly!
  3. This is where you setup the UITableView. You declare that the view controller is the UITableViewdelegate/data source; therefore, all the information required by UITableView will be provided by the view controller. Note that you can actually set the delegate and datasource in a storyboard, if your table view is created there.
Now, add the following method to ViewController.swift:
func showDataForAlbum(albumIndex: Int) {
  // defensive code: make sure the requested index is lower than the amount of albums
  if (albumIndex < allAlbums.count && albumIndex > -1) {
    //fetch the album
    let album = allAlbums[albumIndex]
    // save the albums data to present it later in the tableview
    currentAlbumData = album.ae_tableRepresentation()
  } else {
    currentAlbumData = nil
  }
  // we have the data we need, let's refresh our tableview
  dataTable!.reloadData()
}
showDataForAlbum() fetches the required album data from the array of albums. When you want to present the new data, you just need to call reloadData. This causes UITableView to ask its delegate such things as how many sections should appear in the table view, how many rows in each section, and how each cell should look.
Add the following line to the end of viewDidLoad
self.showDataForAlbum(currentAlbumIndex)
This loads the current album at app launch. And since currentAlbumIndex was previously set to 0, this shows the first album in the collection.
Now it’s time to implement the data source protocol! You can add the list of protocols implemented by the class right on the class declaration line. Or, to keep things tidy you can add them as extensions, which you’re already familiar with.
Add the following extensions to the bottom of the file. Make sure you add these lines after the closing brace of the class definition!
extension ViewController: UITableViewDataSource {
}
 
extension ViewController: UITableViewDelegate {
}
This is how you make your delegate conform to a protocol — think of it as a promise made by the delegate to fulfill the method’s contract. Here, you indicate that ViewController will conform to the UITableViewDataSource and UITableViewDelegate protocols. This way UITableView can be absolutely certain that the required methods are implemented by its delegate.
Add the following code to the UITableViewDataSource extension:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  if let albumData = currentAlbumData {
    return albumData.titles.count
  } else {
    return 0
  }
}
 
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
  if let albumData = currentAlbumData {
    cell.textLabel!.text = albumData.titles[indexPath.row]
    cell.detailTextLabel!.text = albumData.values[indexPath.row]
  }
  return cell
}
tableView(_:numberOfRowsInSection:) returns the number of rows to display in the table view, which matches the number of titles in the data structure.
tableView(_:cellForRowAtIndexPath:) creates and returns a cell with the title and its value.
Note: You can actually add the methods to the main class declaration or to the extension; the compiler doesn’t care that the data source methods are actually inside the UITableViewDataSource extension. For humans reading the code though, this kind of organization really helps with readability.
Build and run your project. Your app should start and present you with the following screen:
designPatternDataTable

Comments

  1. This is a very nice article. thank you for publishing this. i can understand this easily.!!..iOS Swift Online Training

    ReplyDelete

Post a Comment

Popular posts from this blog

iOS Architecture

Property vs Instance Variable (iVar) in Objective-c [Small Concept but Great Understanding..]

setNeedsLayout vs layoutIfNeeded Explained