func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell = tableView.dequeueReusableCellWithIdentifier("dieRoll", forIndexPath: indexPath) as DieResultCell;
let data=myArray[indexPath.row] ;
cell.dieLabel.text="\(data)"
return cell
}
This is fine for a simple table, but I would like to allow for different types of table cells within the view and provide a general routine.The refactoring is to allow the datatype to implement a protocol that defines the nib identifier. In addition a closure will provide a callback that initializes the table cell with the data it is to display.
The protocol is rather simple:
@objc protocol ProvidesCellIdentifier
{
var cellIdentifier:String { get}
}
@objc class RollResult
{
var rollResult:String="";
init(value:String)
{
rollResult=value;
}
}
then add an extension to my RollResult type that supplies that cell identifier:
extension RollResult: ProvidesCellIdentifier
{
var cellIdentifier: String
{
return DieResultCell.cellIdentifier;
}
}
The next step is to modify my table so that it tracks information about the various cells that it can display:
class CellConfigurationInfo
{
var cellIdentifier:String="";
var dataClass:AnyClass=AnyObject.self;
var configuration:((UITableViewCell,AnyObject)->())={(cell:UITableViewCell,value:AnyObject) in };
This is used so that when I display a cell with the given cell identifier, I will call the configuration routine with that data. Note that the default callback doesn't actually do anything:
Now to initialize my table, the following call is used:
tableControl=TableViewDataProvider(self.resultTable)
.addMapping(DieResultCell.cellIdentifier, dataClass: Die.self, configurationRoutine: DieResultCell.dieCellClosure )
Where DieResult Cell is:
class DieResultCell : UITableViewCell
{
@IBOutlet var dieLabel : UILabel
class var cellIdentifier:String { return "dieRoll"};
class var dieCellClosure:(UITableViewCell,AnyObject)->() {
return {(cell:UITableViewCell, value:AnyObject)->() in
let die=value as RollResult;
let dieCell=cell as DieResultCell;
dieCell.dieLabel.text="\(die.rollResult)"
}}
//
// TableViewDataProvider.swift
// SimpleDieRoller
//
// Created by Jon Lundy on 6/28/14.
// Copyright (c) 2014 Jon Lundy. All rights reserved.
//
import Foundation
import UIKit
class CellConfigurationInfo
{
var cellIdentifier:String="";
var dataClass:AnyClass=AnyObject.self;
var configuration:((UITableViewCell,AnyObject)->())={(cell:UITableViewCell,value:AnyObject) in };
}
class TableViewDataProvider : NSObject, UITableViewDataSource,UITableViewDelegate
{
var configurations = Dictionary<String,CellConfigurationInfo>();
let table:UITableView;
init(_ mytable:UITableView)
{
self.table=mytable;
myArray=Array<AnyObject>();
super.init();
self.table.dataSource=self;
self.table.delegate=self;
}
var myArray:Array<AnyObject>;
var cellSelected:((AnyObject)->())={(value:AnyObject) in println("Cell Selected \(value)")};
func addMapping(cellIdentifier:String, dataClass:AnyClass,
configurationRoutine:(UITableViewCell,AnyObject)->()) ->TableViewDataProvider
{
let info=CellConfigurationInfo();
info.cellIdentifier=cellIdentifier;
info.dataClass=dataClass;
info.configuration=configurationRoutine;
configurations.updateValue(info, forKey: cellIdentifier)
return self;
}
func onSelection(selectCall:(AnyObject)->())->TableViewDataProvider
{
cellSelected=selectCall;
return self;
}
func addArray(arrayToWatch:Array<AnyObject>)
{
myArray=arrayToWatch;
self.table.reloadData();
}
func clear()
{
self.myArray.removeAll(keepCapacity: true);
self.table.reloadData();
}
func addItem(itemToAdd:AnyObject)
{
self.myArray.insert(itemToAdd, atIndex: 0);
self.table.reloadData();
}
func updateData()
{
self.table.reloadData();
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
{
return myArray.count;
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
var selectedObject=getObjectAtPath(indexPath);
self.cellSelected(selectedObject);
}
func getObjectAtPath(indexPath:NSIndexPath)->AnyObject
{
return self.myArray[indexPath.row];
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let data=myArray[indexPath.row] ;
let myclass=data.classForCoder
println("Getting object for class \(myclass)")
let dataProtocol = data as ProvidesCellIdentifier
var config=configurations[dataProtocol.cellIdentifier]!
let cell = tableView.dequeueReusableCellWithIdentifier(config.cellIdentifier, forIndexPath: indexPath) as UITableViewCell;
config.configuration(cell,data);
return cell;
}
}