Saturday, July 12, 2014

A simple table provider

For my next task I wanted to do a first cut at a simple table view.  I personally have found that the having the TableViewDataSource and TableViewDelegate be my view controller to mean duplicated code.  My first version is just a simple array of 'any object' that can be managed by a table view.

In this case I'm trying a slightly different UI than most.  I have a picker view and a table view on the same window.


In this case the top is the picker view, and the bottom is the table view.  Right now I just made a very primitive custom view that had a single 'label'.  In Xcode I gave it an identifier of 'dieRoll'.

The code to hook up my view to the table is:


        tableControl=TableViewDataProvider(self.resultTable)

To add a new row to the table I do:


            let result=currentRoller!.roll();
            self.tableControl!.addItem(result)

In this case result is an instance of my 'Die' class:

Finally the class for the table controller is:

Note that I have code in here where I can get selection events, but I currently just use a segue in interface builder for going to a subview.


class TableViewDataProvider : NSObject, UITableViewDataSource,UITableViewDelegate
{
    
    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 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 cell = tableView.dequeueReusableCellWithIdentifier("dieRoll", forIndexPath: indexPath) as DieResultCell;
        let data=myArray[indexPath.row] ;
        cell.dieLabel.text="\(data)"
        
        return cell

    }


This is rather primitive, but a starting point. I've abstracted from my view the ability to display an array.  However this currently has a hardcoded 'cell manager', which gets the proper cell, and initializes it.  In addition it only works for arrays, I would also like it to work for a NSFetchedResultsController.


Refactoring goals:

  • Pass in the configuration for determining which cell to use, and how to initialize it.
  • Abstract the management of data to a subclass to allow other sources (such as CoreData, web, etc).

No comments:

Post a Comment