Home iOS & Swift Books iOS Apprentice

24
Delegates & Protocols Written by Eli Ganim

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

You now have an Edit High Score screen showing a keyboard that lets the user enter text. The app also properly validates the input so that you’ll never end up with text that’s empty.

But how do you get this text into HighScoreItem and add it to items on the High Scores screen? That’s the topic that this chapter will explore.

Updating HighScoreItem

For editing to work, you’ll have to get the Edit High Score screen to notify the High Scores View Controller of the updated HighScoreItem. This is one of the fundamental tasks that every iOS app needs to do: Send messages from one view controller to another.

Sending a HighScoreItem object to the screen with the items array
Sending a HighScoreItem object to the screen with the items array

The messy way

Exercise: How would you tackle this problem? done() needs to update HighScoreItem with the text from the text field, which is easy, then update it in the Table view in HighScoreViewController, which is not so easy.

class EditHighScoreViewController: UITableViewController, . . . {
  // This variable refers to the other view controller
  var highScoresViewController: HighScoresViewController

  @IBAction func done() {
    highScoreItem.name = textField.text!

    // Directly call a method from HighScoresViewController
    highScoresViewController.update(item)
  }
}

The delegate way

You’ve already seen delegates in a few different places: The Table view has a delegate that responds to taps on the rows. The text field has a delegate that you used to validate the length of the text. The app also has something named the AppDelegate (see the project navigator).

Screen A launches screen B and becomes its delegate
Qkfioj A roacwjes nhzoev C owx nucowob apf vumagoma

The delegate protocol

➤ At the top of EditHighScoreViewController.swift, add the following after the import line but before the class line — it’s not part of the EditHighScoreViewController object:

protocol EditHighScoreViewControllerDelegate: class {
  func editHighScoreViewControllerDidCancel(
    _ controller: EditHighScoreViewController)
  func editHighScoreViewController(
    _ controller: EditHighScoreViewController, 
    didFinishEditing item: HighScoreItem)
}

Protocols [TODO: delete me?]

In Swift, a protocol has nothing to do with computer networks or meeting royalty, it’s simply a name for a group of methods.

var delegate: EditHighScoreViewControllerDelegate

Notifying the delegate

You’re not done in EditHighScoreViewController.swift yet. The view controller needs a property that it can use to refer to the delegate; you’ll take care of that now.

weak var delegate: EditHighScoreViewControllerDelegate?
var highScoreItem: HighScoreItem!
@IBAction func cancel() {
  delegate?.editHighScoreViewControllerDidCancel(self)
}

@IBAction func done() {
  highScoreItem.name = textField.text!

  delegate?.editHighScoreViewController(self, didFinishEditing: highScoreItem)
}

Optionals

You read a few times before that variables and constants in Swift must always have a value. In other programming languages, the special symbol nil or NULL is often used to indicate that a variable has no value. Swift doesn’t allow this for normal variables.

weak var delegate: EditHighScoreViewControllerDelegate?
delegate?.editHighScoreViewControllerDidCancel(self)

Conforming to the delegate protocol

Before you can give EditHighScoreViewController its delegate, you need to make HighScoresViewController suitable to play the role of a delegate.

class HighScoresViewController: UITableViewController, 
                               EditHighScoreViewControllerDelegate {
Xcode warns about not conforming to protocol
Jsoqi lunkw ecean sel suqzalrogf ko mraheqow

// MARK:- Edit High Score ViewController Delegates
func editHighScoreViewControllerDidCancel(
                       _ controller: EditHighScoreViewController) {
  navigationController?.popViewController(animated:true)
}
func editHighScoreViewController(
               _ controller: EditHighScoreViewController, 
       didFinishEditing item: HighScoreItem) {
  navigationController?.popViewController(animated:true)
}
// MARK:- Navigation
override func prepare(for segue: UIStoryboardSegue, 
                         sender: Any?) {
  // 1
  let controller = segue.destination as! EditHighScoreViewController
  // 2
  controller.delegate = self
  // 3
  if let indexPath = tableView.indexPath(for: sender as! UITableViewCell) {
    controller.highScoreItem = items[indexPath.row]
  }
}
textField.text = highScoreItem.name

Updating the table view

If you change the name and click Done, you’ll update the item itself, but the Table view will still show the old value. That’s because you didn’t tell the Table view to refresh the cell after the data changed. Time to fix it!

func editHighScoreViewController(_ controller: EditHighScoreViewController,
                                 didFinishEditing item: HighScoreItem) {
  // 1
  if let index = items.firstIndex(of: item) {
    // 2
    let indexPath = IndexPath(row: index, section: 0)
    let indexPaths = [indexPath]
    // 3
    tableView.reloadRows(at: indexPaths, with: .automatic)
  }
  // 4
  PersistencyHelper.saveHighScores(items)
  navigationController?.popViewController(animated:true)
}
New Xcode error
Tim Fpanu uzcoz

class HighScoreItem : NSObject, Codable {

Weak

I promised you an explanation of the weak keyword. Relationships between objects can be weak or strong. You use weak relationships to avoid an ownership cycle.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.