Slide 1

Slide 1 text

Building TableViews with Swift and iOS8 @NatashaTheRobot

Slide 2

Slide 2 text

TableView Basics Seinfeld Quotes App

Slide 3

Slide 3 text

⌘ + N

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Data Source let quotes = Quote.allQuotes()

Slide 9

Slide 9 text

Self Sizing Table View Cell

Slide 10

Slide 10 text

Self Sizing Table View Cell import UIKit class QuotesTableViewController: UITableViewController { /*...*/ override func viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 89 tableView.rowHeight = UITableViewAutomaticDimension } /*...*/ }

Slide 11

Slide 11 text

import UIKit class TwoLabelTableViewCell: UITableViewCell { @IBOutlet weak private var headerLabel: UILabel! @IBOutlet weak private var subheadLabel: UILabel! func configure(#headerText: String, subheadText: String) { headerLabel.text = headerText headerLabel.accessibilityLabel = headerText subheadLabel.text = "- \(subheadText)" subheadLabel.accessibilityLabel = subheadText } }

Slide 12

Slide 12 text

class QuotesTableViewController: UITableViewController { private let quotes = Quote.allQuotes() private let quoteCellIdentifier = "quoteCell" override func viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 89 tableView.rowHeight = UITableViewAutomaticDimension } // MARK: - Table view data source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return quotes.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(quoteCellIdentifier) as TwoLabelTableViewCell let quote = quotes[indexPath.row] cell.configure(headerText: quote.content, subheadText: quote.scene) return cell } }

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Dynamic Type class TwoLabelTableViewCell: UITableViewCell { @IBOutlet weak private var headerLabel: UILabel! @IBOutlet weak private var subheadLabel: UILabel! func configure(#headerText: String, subheadText: String) { headerLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline) subheadLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline) /*...*/ } /*...*/ }

Slide 18

Slide 18 text

Hide Navigation Bar on Scroll class QuotesTableViewController: UITableViewController { // ** // override func viewDidLoad() { super.viewDidLoad() navigationController?.hidesBarsOnSwipe = true // ** // } // ** // }

Slide 19

Slide 19 text

Default Parameter Values func configure(#headerText: String, subheadText: String, textColor: UIColor = UIColor.blackColor()) { headerLabel.textColor = textColor subheadLabel.textColor = textColor /* ... */ }

Slide 20

Slide 20 text

MVVM Model View ViewModel class Quote { let content: String let scene: String /* ... */ init(content: String, scene: String) { self.content = content self.scene = scene } }

Slide 21

Slide 21 text

View Model class QuoteViewModel { var quoteContent: String? var quoteScene: String? let quoteContentPlaceholder = "Quote Content" let quoteScenePlaceholder = "Scene Description" init(quoteContent: String? = nil, quoteScene: String? = nil) { self.quoteContent = quoteContent self.quoteContent = quoteScene } }

Slide 22

Slide 22 text

View Model class CreateQuoteTableViewController: UITableViewController { private let quoteViewModel = QuoteViewModel() /* ... */ }

Slide 23

Slide 23 text

Alternate Data Source Structures Enumerations

Slide 24

Slide 24 text

class CreateQuoteTableViewController: UITableViewController { private let quoteViewModel = QuoteViewModel() /* ... */ private enum QuoteField: Int { case Content, Scene func placeholder(#quoteViewModel: QuoteViewModel) -> String { switch self { case .Content: return quoteViewModel.quoteContentPlaceholder case .Scene: return quoteViewModel.quoteScenePlaceholder } } func text(#quoteViewModel: QuoteViewModel) -> String? { switch self { case .Content: return quoteViewModel.quoteContent case .Scene: return quoteViewModel.quoteScene } } func updateQuoteWithText(text: String, quoteViewModel: QuoteViewModel) { switch self { case .Content: quoteViewModel.quoteContent = text case .Scene: quoteViewModel.quoteScene = text } } /* ... */ }

Slide 25

Slide 25 text

Using Enums override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as TextInputTableViewCell if let quoteField = QuoteField.fromRaw(indexPath.row) { let text = quoteField.text(quoteViewModel: quoteViewModel) let placeholder = quoteField.placeholder(quoteViewModel: quoteViewModel) /* ... */ } return cell }

Slide 26

Slide 26 text

Using Closures import UIKit class TextInputTableViewCell: UITableViewCell, UITextFieldDelegate { @IBOutlet weak private var textField: UITextField! typealias textFieldChangedHandlerType = (String) -> Void private var textFieldChangedHander: textFieldChangedHandlerType? override func awakeFromNib() { textField.delegate = self } func configure(#text: String?, placeholder: String, textFieldChangedHandler: textFieldChangedHandlerType?) { textField.placeholder = placeholder textField.text = text textField.accessibilityLabel = placeholder textField.accessibilityValue = text self.textFieldChangedHander = textFieldChangedHandler } // MARK: Text Field Delegate func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if let textFieldChangedHandler = textFieldChangedHander { textFieldChangedHandler(textField.text) } return true } }

Slide 27

Slide 27 text

Using Closures override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as TextInputTableViewCell if let quoteField = QuoteField.fromRaw(indexPath.row) { let text = quoteField.text(quoteViewModel: quoteViewModel) let placeholder = quoteField.placeholder(quoteViewModel: quoteViewModel) cell.configure(text: text, placeholder: placeholder, textFieldChangedHandler: { [weak self] (newText) in if let strongSelf = self { quoteField.updateQuoteWithText(newText, quoteViewModel: strongSelf.quoteViewModel) } }) } return cell }

Slide 28

Slide 28 text

A Swift Summary iOS8 Features — Self Sizing Table View Cells — Dynamic Type — Hide Navigation Bar

Slide 29

Slide 29 text

A Swift Summary Swift Features — Enumerations — Default Parameter Values — Functions / Closures

Slide 30

Slide 30 text

A Swift Summary Design Patterns — MVVM

Slide 31

Slide 31 text

Questions? @NatashaTheRobot