Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Complex iOS UITableViews

Axel Rivera
November 30, 2015

Complex iOS UITableViews

Presented at the first Fullstack Nights at the Puerto Rico Science and Technology TRUST.

Axel Rivera

November 30, 2015
Tweet

More Decks by Axel Rivera

Other Decks in Programming

Transcript

  1. Delegation class MyController: UIViewController { override func viewDidLoad() { super.viewDidLoad()

    tableView = UITableView(frame: CGRectZero, style: .Plain) tableView.dataSource = self tableView.delegate = self } }
  2. Data Source extension MyController: UITableViewDelegate { func numberOfSectionsInTableView(tableView: UITableView) ->

    Int { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { return UITableViewCell(style: .Default, reuseIdentifier: nil) } }
  3. Delegate extension MyController: UITableViewDelegate { func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:

    NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath, animated: true) } func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat return 44.0 } }
  4. Most Common Scenario 4 All Rows Have Same Type 4

    Single Section 4 Objects are Stored in an Array
  5. All Rows are the Same func numberOfSectionsInTableView(tableView: UITableView) -> Int

    { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return arrayOfObjects.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as UITableViewCell! if cell == nil { cell = UITableViewCell(style: .Default, reuseIdentifier: CellIdentifier) } let myObject = arrayOfObjects[indexPath.row] cell.textLabel?.text = myObject.text return cell }
  6. Complex Scenario 4 Rows are of Different Types 4 Multiple

    Sections 4 Content Not Defined as Array
  7. func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 2 } func

    tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if section == 0 { return 1 } else if section == 1 { return 2 } return return 0 }
  8. func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { if

    indexPath.section == 0 { var cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as UITableViewCell! return cell } if indexPath.section == 1 { if indexPath.row == 0 { var cell = tableView.dequeueReusableCellWithIdentifier(SecondIdentifier) as UITableViewCell! return cell } var cell = tableView.dequeueReusableCellWithIdentifier(SecondIdentifier) as UITableViewCell! return cell } return UITableViewCell(style: .Default, reuseIdentifier: nil) }
  9. if indexPath.section == 0 { var cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as

    UITableViewCell! if cell == nil { cell = UITableViewCell(style: .Default, reuseIdentifier: CellIdentifier) } let myObject = arrayOfObjects[indexPath.row] cell.textLabel?.text = myObject.text return cell }
  10. if indexPath.section == 1 { if indexPath.row == 0 {

    var cell = tableView.dequeueReusableCellWithIdentifier(AnotherIdentifier) as UITableViewCell! if cell == nil { cell = UITableViewCell(style: .Subtitle, reuseIdentifier: AnotherIdentifier) } cell.textLabel?.text = "This Content Might Be Fixed" cell.detailTextLabel?.text = "Common in Settings" return cell } var cell = tableView.dequeueReusableCellWithIdentifier(AnotherIdentifier) as UITableViewCell! if cell == nil { cell = UITableViewCell(style: .Default, reuseIdentifier: AnotherIdentifier) let customSwitch = UISwitch() cell.accessoryView = customSwitch self.customSwitch = customSwitch } cell.textLabel?.text = "You Can Add Custom Controls to Default Views" if let customSwitch = cell.accessoryView as? UISwitch { customSwitch.on = NSUserDefaults.standardUserDefaults().objectForKey("my_key") as? Bool ?? false } return cell }
  11. See Any Problems? 4 Nested structures can be complex 4

    What happens if you decide to change the order?
  12. Can Add Helper Methods to Manage Cells by passing indexPath

    as Parameter 4 I don't do it 4 Have to use conditionals anyway (indexPath.section and indexPath.row) 4 Cell UI Logic belongs in Data Source and Delegate methods to improve readability (My Opinion)
  13. Goals 4 Single Data Source Array for Everything 4 Make

    UITableView logic SECTION and ROW agnostic 4 Improve Readability 4 Decrease Number of Lines 4 Keep Cell management in Data Source and Delegate methods
  14. New Method func updateDataSource(reload reload: Bool = true) { var

    content: TableRow! var rows = TableRowArray() var sections = TableSectionArray() content = TableRow(text: "Text Label", detail: "Detail Text") content.groupIdentifier = CellIdentifier content.identifier = "sample_identifier" content.height = 54.0 rows.append(content) sections.append(TableSection(title: "Section 1", rows: rows)) dataSource = sections if reload { tableView.reloadData() } }
  15. class MyController: UIViewController { var tableView: UITableView! var dataSource =

    TableSectionArray() override viewDidLoad() { super.viewDidLoad() // Add UI Stuff Here // Update Data Source at the end updateDataSource() } }
  16. Number of Sections and Rows func numberOfSectionsInTableView(tableView: UITableView) -> Int

    { return dataSource.count } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataSource[indexPath.section].rows.count }
  17. Create Cell func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

    { let row = dataSource[indexPath.section].rows[indexPath.row] let groupIdentifier = row.groupIdentifier ?? String() if groupIdentifier == CellIdentifier { var cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as UITableViewCell! if cell == nil { cell = UITableViewCell(style: .Default, reuseIdentifier: CellIdentifier) } cell.textLabel?.text = row.text return cell } return UITableViewCell(style: .Default, reuseIdentifier: nil) }
  18. Cell Height func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

    { return dataSource[indexPath.section].rows[indexPath.row].height ?? 44.0 }
  19. Cell Selection func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath,

    animated: true) let row = dataSource[indexPath.section].rows[indexPath.row] let identifier = row.identifier ?? String() if identifier == "custom_identifier" { // Do Something Here } }
  20. Section struct TableSection { var groupIdentifier: String? var identifier: String?

    var title: String? var footer: String? var rows = TableRowArray() var userInfo = TableInfo() init(title: String?, rows: TableRowArray) { self.title = title self.rows = rows } }
  21. Row struct TableRow { var rowType: TableRowType = .Custom var

    identifier: String? var groupIdentifier: String? var text: String? var detail: String? var view: UIView? var userInfo = TableInfo() var object: Any? var height: CGFloat? init(type: TableRowType) { self.rowType = type } init(type: TableRowType, text: String?, detail: String?) { self.rowType = type self.text = text self.detail = detail } }