Building TableViews with Swift and iOS8

Building TableViews with Swift and iOS8

Presented at the SLUG Meetup on 09/10/2014: http://www.meetup.com/swift-language/events/201151762/

Source Code: https://github.com/NatashaTheRobot/SeinfeldQuotes

TableViews are the foundation of most (non-gaming) iOS applications, and Swift provides several unexplored patterns for approaching TableViews moving forward. Experienced Objective-C programmers will learn how to apply "Swift-thinking" when approaching an iOS8 TableView. New iOS developers will learn the basics of TableViews and how to use them in their own iOS projects.

52a5c6ad5e59109f1fcaf4eca9e2414f?s=128

Natasha Murashev

September 10, 2014
Tweet

Transcript

  1. Building TableViews with Swift and iOS8 @NatashaTheRobot

  2. TableView Basics Seinfeld Quotes App

  3. ⌘ + N

  4. None
  5. None
  6. None
  7. None
  8. Data Source let quotes = Quote.allQuotes()

  9. Self Sizing Table View Cell

  10. Self Sizing Table View Cell import UIKit class QuotesTableViewController: UITableViewController

    { /*...*/ override func viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 89 tableView.rowHeight = UITableViewAutomaticDimension } /*...*/ }
  11. 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 } }
  12. 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 } }
  13. None
  14. None
  15. None
  16. None
  17. 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) /*...*/ } /*...*/ }
  18. Hide Navigation Bar on Scroll class QuotesTableViewController: UITableViewController { //

    ** // override func viewDidLoad() { super.viewDidLoad() navigationController?.hidesBarsOnSwipe = true // ** // } // ** // }
  19. Default Parameter Values func configure(#headerText: String, subheadText: String, textColor: UIColor

    = UIColor.blackColor()) { headerLabel.textColor = textColor subheadLabel.textColor = textColor /* ... */ }
  20. MVVM Model View ViewModel class Quote { let content: String

    let scene: String /* ... */ init(content: String, scene: String) { self.content = content self.scene = scene } }
  21. 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 } }
  22. View Model class CreateQuoteTableViewController: UITableViewController { private let quoteViewModel =

    QuoteViewModel() /* ... */ }
  23. Alternate Data Source Structures Enumerations

  24. 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 } } /* ... */ }
  25. 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 }
  26. 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 } }
  27. 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 }
  28. A Swift Summary iOS8 Features — Self Sizing Table View

    Cells — Dynamic Type — Hide Navigation Bar
  29. A Swift Summary Swift Features — Enumerations — Default Parameter

    Values — Functions / Closures
  30. A Swift Summary Design Patterns — MVVM

  31. Questions? @NatashaTheRobot