Sunday, July 20, 2014

Refactoring the table provider

As you recall, the last version of the table provider had a hardcoded cell provider:
 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}

}

I encapsulate my roll result into a cass, and an associated data type.  This will allow for more flexibility, and uses the Swift extension mechanism.

@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)"
        
        }}


The end result is a flexible table data source that can display different data types:  The full source for the TableViewProvider is below:
//
//  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;
        
    }

    
    

}

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).

Saturday, June 28, 2014

Version 2 of swift UI picker view

This version's Goals

The previous iteration of the picker view was great, but only supported pure text.  The next version supports using an object as well as supplying more utility routines to provide data.

For this version I want to clean up the API and make it more general and add the following capabilities:


  • Be able to use an object to supply the data, and make that object available when it is picked
  • Have an easier interface to provide data to the picker view
  • Be able to have varying widths when implementing displaying the text.

These goals will implement the vast majority of pickers required, the main item missing will be the ability to provide custom views for the picker images,

The previous version supported an object, but that object had to implement a protocol and it was not a very general solution. This version will keep the implementation of the object pure, and let the picker view work with pretty much any object.

Calling Implementation

Die data type

My datatype is a very simple die type.  It contains the ability to define the die in the constructor (initializer) of the data type, as well as a method that generates a random number:
@objc class Die
{
    var dieType:Int
    
    init(_ die:Int)
    {
        dieType=die;
    }

    
    func roll () -> Int
    {
        let result=Int(arc4random_uniform(UInt32(dieType)));
        
        return result + 1;
    }

}
Note that my previous solution had the Die implementing a protocol and the picker provider.

Creating the dice

When creating the dice array, we can use the map function to create the array just like before:
let dieTypes=[4,6,8,10,12,20].map{ (var number) -> Die in
            return Die(number);
         };
In this case since the die type is no longer implementing a protocol, I supply a simple closure that takes an AnyObject, casts it to a Die and supplies the text I want:
 let dieToText={ (value:AnyObject)->String in
            let die = value as Die;
            return "d\(die.dieType)";
        };
This is a more general solution, since I can now decorate any object with a simple provider, and it should scale to supplying views as well as title strings.

Creating the picker view

The big change was that I modified the picker view to have a fluent interface.  Objective C and Swift supply some of these capabilities, but in this case I wanted to support many different objects without writing a ton of constructors. In this case I also supply a 'weight'. The sum of all weights is added up (it defaults to 1), and then that is used as the basic to calculate the width of each component.
I also added methods that create numeric ranges.

delegate=PickerProvider().changeCallback(returnValue)
            .addComponentRange(1, maxValue: 20).setWeight(1.5)
            .addComponent(dieTypes)
            .setTextProvider(dieToText).setWeight(3)
            .addComponent(["+","-"]).setWeight(0.5)
            .addComponentRange(0,maxValue:30).setWeight(1.2);

The callback

The callback for when an item is selected will create a roller object with the selected values. Right now I have to do a lot of casting, I'm not sure of a good solution for that, but since I supply the components at the same location as I supply it, then it should be relatively type safe.
 func getDieText(value:AnyObject[])->String
    {
        var numDice:Int=value[0] as Int;
        var dieType:Die=value[1] as Die;
        var modifier:String=value[2] as String;
        var num:Int=value[3] as Int;
        
        currentRoller = Roller(numDice: numDice, dieType: dieType, modSign: modifier, modifier: num)
        
        return "\(numDice)d\(dieType.dieType)\(modifier)\(num)";
        
    }

The Roller is simple:
@objc class Roller
{
    var myDice=0;
    var myDie:Die;
    var myMod:String;
    var myModifier:Int;
    
    init(numDice:Int, dieType:Die, modSign:String, modifier:Int)
    {
        myDice=numDice;
        myDie=dieType;
        myMod=modSign;
        myModifier=modifier;
    }
    func roll()->String
    {
        var result=0;
        var stringResult="\(myDie.dieType):"
        
        for i in 1...myDice
        {
            if i != 1
            {
                stringResult+=",";
            }
            
            let roll = myDie.roll();
            result += roll;
            stringResult += "\(roll)";
        }
        if myModifier > 0
        {
        if (myMod == "+")
        {
            result += myModifier;
            
            stringResult += "+\(myModifier)"
        }
        else
        {
            stringResult += "\(myModifier)"
            result -= myModifier;
        }
        }
        stringResult += "=\(result)"
        return stringResult;
    
    }
}

Picker Provider implementation


//
//  DieRollDataSource.swift
//  SimpleDieRoller
//
//  Created by Jon Lundy on 6/4/14.
//  Copyright (c) 2014 Jon Lundy. All rights reserved.
//

import Foundation
import UIKit

// Component Info keeps information about each component. 
// It uses an array to track the data, as well suppling
// a text provider that converts an item in the array to
// a string.  Note that I have a placeholder for a view
// provider, but that is not implemented yet.
class ComponentInfo
{
    // The items contained within this component.
    var componentArray:Array<AnyObject>;
    // The default text provider just casts the object to value.
    // Convert an item to a string. The default is
    // the built in Swift conversion.
    var textProvider:((AnyObject)->String)={(value:AnyObject) in return "\(value)"};
    
    // Not implemented yet.
    var viewProvider:((AnyObject)->UIView)?=nil;
    // By default just use a weight of 1.
    var weight:Double=1;
    
    // A simple constructor.
    init(_ array:Array<AnyObject>)
    {
        componentArray=array;
    }
}
//the core class for the picker.
class PickerProvider :NSObject, UIPickerViewDataSource,UIPickerViewDelegate
{
    
    var componentArrays:Array<ComponentInfo>=Array<ComponentInfo>();
    var callback:(AnyObject[])->()  ;
   
    
    // Change the default callback, the default is to do
    // nothing.
    func  changeCallback(selectedCall:(AnyObject[])->()) ->PickerProvider
    {
        println("Entering setCallback");
        
        callback=selectedCall;
        return self;
    }
    // Set the text provider for the last component added.
    func setTextProvider(provider:(AnyObject)->String)->PickerProvider
    {
        componentArrays[componentArrays.count-1].textProvider=provider;

        return self;
    }
    // Set the weight for the last callback.
    func setWeight(weight:Double) ->PickerProvider
    {
        componentArrays[componentArrays.count-1].weight=weight;
        return self;
    }
    // Add a component
    func  addComponent(newArray:Array<AnyObject> )->PickerProvider
    {
        var comp = ComponentInfo(newArray);
        componentArrays.append(comp);
        return self;
    }
    
    // Add a range of numbers.
    func addComponentRange(minValue:Int, maxValue:Int)->PickerProvider
    {
        var newarray=getArray(minValue, maxNum:maxValue)
        addComponent(newarray);
        return self;
    }
    
    // Create an array of numbers.
    func getArray(minNum:Int,maxNum:Int) -> Int[]
    {
        var returnValue=Int[]();
        for i in minNum...maxNum
        {
            returnValue.append(i);
        }
        return returnValue;
    }
    
    // The initial method will take a callback for when a selection si made as well
    // as the array of objects to display.
    init()
    {
        callback = { (selectedRows: AnyObject[])->() in
        };

          
    }
    
    // Standard override return the number of rows for the given component.
    func pickerView(pickerview: UIPickerView!,numberOfRowsInComponent component: Int)
    -> Int
    {
        let array=getArray(component);
        return array.count;
        
    }
    
    // returns the number of 'columns' to display.
    func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int
    {
        return componentArrays.count;
    }
    
    // Internal function to retrieve a specific array.
    func getArray( compNum:Int) -> Array<AnyObject>
    {
        return componentArrays[compNum].componentArray;
    }
    
    
    


    // Get the value for a given component.  Just use the standard swift to make it into a string.
    func pickerView(pickerView: UIPickerView!, titleForRow row: Int, forComponent component: Int) -> String
    {
        var comp=componentArrays[component];
      
        let value : AnyObject=comp.componentArray[row];
        return comp.textProvider(value);
    }

    
    // Right now weight all arrays equally for the size.  For a real approach we would need to be
    
    func pickerView(pickerView: UIPickerView!, widthForComponent component: Int) -> CGFloat
    {
        var totalWeight:Double=0.0;
        var myComponent=self.componentArrays[component].weight;
        
        for  component in self.componentArrays
        {
            totalWeight += component.weight;
        }
        let width:Double=pickerView.frame.width-10;
        let value=width / totalWeight * myComponent;
        return value;
    }
    
    func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int)
    {
        var returnValue=AnyObject[]();
        for i in 0..componentArrays.count
        {
            let selected=pickerView.selectedRowInComponent(i)
            let array=getArray(i);
            let value=array[selected]
            returnValue.append(value);
        }
        self.callback(returnValue);

    }


    

}

What's next:

The next version should support:
The ability to have a custom view in addition to pure text in the picker.
The ability to have the contents of some of the components change based upon selections in the previous components (for example the date picker won't allow you to pick Day 31 for February.

Wednesday, June 18, 2014

Cannot downcast from 'AnyObject' to non-@objc protocol type

The next item I wished to do was to pass in an object to my picker and let it be a choice.  I defined a simple object type of Die, which represents a type of die.

I could not find a way to have interpolation work with the object, for "\(value)", so I decided to have a protocol that can be checked for.

I defined the following protocol:
protocol ProvidesTextValue
{
    var textValue:String { get}

}

With the following usage:
 func pickerView(pickerView: UIPickerView!, titleForRow row: Int, forComponent component: Int) -> String
    {
        let array=getArray(component);

        let value : AnyObject=array[row];
        if value is ProvidesTextValue
        {
            let textProvider=value as ProvidesTextValue
            return "\(textProvider.textValue)"
        }
            return "\(value)";
    }

Which resulted in the error:
DieRollDataSource.swift:61:18: Cannot downcast from 'AnyObject' to non-@objc protocol type 'ProvidesTextValue'

The Swift Programming guide provides the following guidance:

NOTE
You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance.
Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types.

So I had to modify the protocol definition to be:
@objc protocol ProvidesTextValue
{
    var textValue:String { get}
}


This resulted in a runtime error with the very 'useful' error message:
** NSForwarding: warning: object 0x110fa0000 of class '_TtC15SimpleDieRoller3Die' does not implement methodSignatureForSelector: -- trouble ahead

I then modified the class definition with @objc as well, which solved the problem:
@objc class Die : ProvidesTextValue
{
    var dieType:Int
    
    init(die:Int)
    {
        dieType=die;
    }

    var textValue:String { return "\(dieType)" }


}

Monday, June 16, 2014

A first cut at a swift library to display a UIPickerView

Below is my first cut at creating a class that manages the data for a picker view.  The standard examples have your view controller managing the rows and data for the picker.  I think that this is a bad connection of concerns, so I wanted a generic class that will manage the data for me.

The example is a simple polyhedral dice roller, which lets you pick a number of dice, of a certain type, and add a modifier.

Below is a screenshot of the picker.

As you can see I just have a simple picker at the top of the screen.  Right now all it does is print out the results to the console:

selected row [1, d8, +, 0]
selected row [3, d8, +, 0]

selected row [3, d8, +, 2]


The view code is just concerned with establishing the data that we wish to display:

 var delegate:PickerProvider? = nil;
  
    init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)
    {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    func getArray(minNum:Int,maxNum:Int) -> Int[]
    {
        var returnValue=Int[]();
        for i in minNum...maxNum
        {
            returnValue.append(i);
        }
        return returnValue;
    }
    
    
    init(coder aDecoder: NSCoder!)
    {
        delegate=nil;
        super.init(coder:aDecoder)
    }
   
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Create an array of numbers for dice.  Use the map function to prepend a 'd' in
        // front of them.
        let dieTypes=[4,6,8,10,12,20].map{ (var number) -> String in
            return "d\(number)";
         };
        
       
        // Note that this is actually a (selectedRows:AnyObject[])->() even though it is
        // declared as (selectedRows:AnyObject[]).  If you declare the paraemter of the method
        // to be (value:AnyObject[]) you will get a compile error.
        let returnValue = { (selectedRows: AnyObject[])->() in
            println("selected row \(selectedRows)");
        };
        
        let numDice=getArray(1,maxNum:20);
        let modifiers=getArray(0,maxNum:30);
        let modRolls=["+","-"];
        
        // Pass the callback to the new delegate, as well as the list of arrays.
         delegate=PickerProvider(selectedCall:returnValue
            ,arrays:numDice,dieTypes,modRolls,modifiers);

        // Set the picker view to use the subclass as both a delgate and dataSource.
        pickerView.dataSource=delegate;
        pickerView.delegate=delegate;
    }

    @IBOutlet var pickerView : UIPickerView
  
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    

I started from a simple 'single view' template, added a picker view, and set the delegate to be 'pickerView'.

The core of the logic is in the PickerProvider class, this class is designed to be a general supplier of picker information.  Right now it only displays text titles, and will subdivide the picker into equal segments.

class PickerProvider :NSObject, UIPickerViewDataSource,UIPickerViewDelegate
{
    
    var myarrays:Array<Array<AnyObject>>;
    var callback:(value:AnyObject[])->();
   
    
    // The initial method will take a callback for when a selection si made as well
    // as the array of objects to display.
    init(selectedCall:(value:AnyObject[])->(), arrays: Array<AnyObject> ... )
    {
        myarrays=arrays;
        callback=selectedCall
    }
    
    // Standard override return the number of rows for the given component.
    func pickerView(pickerview: UIPickerView!,numberOfRowsInComponent component: Int)
    -> Int
    {
        let array=getArray(component);
        return array.count;
        
    }
    
    // returns the number of 'columns' to display.
    func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int
    {
        return myarrays.count;
    }
    
    // Internal function to retrieve a specific array.
    func getArray( compNum:Int) -> Array<AnyObject>
    {
        return myarrays[compNum];
    }
    
    
    


    // Get the value for a given component.  Just use the standard swift to make it into a string.
    func pickerView(pickerView: UIPickerView!, titleForRow row: Int, forComponent component: Int) -> String
    {
        let array=getArray(component);

        let value : AnyObject=array[row];
        return "\(value)";
    }
    
    // Right now weight all arrays equally for the size.  For a real approach we would need to be
    
    func pickerView(pickerView: UIPickerView!, widthForComponent component: Int) -> CGFloat
    {
        let numComp:NSNumber=self.numberOfComponentsInPickerView(pickerView);
        let width:Double=pickerView.frame.width;
        let value=width / numComp.doubleValue;
        return value;
    }
    
    func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int)
    {
        var returnValue=AnyObject[]();
        for i in 0..myarrays.count
        {
            let selected=pickerView.selectedRowInComponent(i)
            let array=getArray(i);
            let value=array[selected]
            returnValue.append(value);
        }
        self.callback(value:returnValue);

    }
    

}

The core of the logic is in the PickerProvider class, this class is designed to be a general supplier of picker information.  Right now it only displays text titles, and will subdivide the picker into equal segments.

Overall I would say that Swift makes for better written code.  I've done similiar constructions in Objective-C, and this is far cleaner.  The code is very readable, and barring a few quirks of Swift fairly easy to write.

This examples shows several usages of Swift constructs, the Closures are easier to write than blocks and are first class citizens.  The map function is very neat and shows the ability to transform lists.

List creation and manipulation is far less verbose than in Objective-C, as is displaying primitives as a string.