I started a project with Objective-C and rewrote it with Swift. The project contains two UITableViewControllers: MasterViewController and DetailViewController. MasterViewController is linked to DetailViewController with a segue.
MasterViewController has two UITableViewCells. The cell with indexPath [0, 0] has a detailTextLabel that displays a String. Each time I click on this cell, I go to the DetailViewController which, in this case, displays a list of Strings. The cell with indexPath [0, 1] has a detailTextLabel that displays an Int. Each time I click on this cell, I go to the DetailViewController, which in this case, displays a list of Ints.
Furthermore, when I select a cell in DetailViewController, it displays a checkmark and updates the MasterViewController related cell which triggered the segue.
Here is a picture of the different scenes of the project:

And here is my code:
MasterViewController
class MasterViewController: UITableViewController {
var myString = "Yellow"
var myInt = 16
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "attributeChangeMethod:", name: "attributeChange", object: nil)
}
func attributeChangeMethod(notif: NSNotification) {
if let passedString: AnyObject = notif.userInfo?["String"] {
myString = passedString as String
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 0, inSection: 0)], withRowAnimation: .Automatic)
}
if let passedInt: AnyObject = notif.userInfo?["Int"] {
myInt = passedInt as Int
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 1, inSection: 0)], withRowAnimation: .Automatic)
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: "attributeChange", object:nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
if indexPath.row == 0 {
cell.textLabel?.text = "My string"
cell.detailTextLabel?.text = myString
}
if indexPath.row == 1 {
cell.textLabel?.text = "My int"
cell.detailTextLabel?.text = "\(myInt)"
}
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let controller = segue.destinationViewController as DetailViewController
if sender as? UITableViewCell == tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)) {
controller.identifier = "String"
controller.passedString = myString
}
if sender as? UITableViewCell == tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 1, inSection: 0)) {
controller.identifier = "Int"
controller.passedInt = myInt
}
}
}
DetailViewController
class DetailViewController: UITableViewController {
var identifier: String!
var passedString: String!
var passedInt: Int!
var array: [Any]!
override func viewDidLoad() {
super.viewDidLoad()
if identifier == "String" {
title = "Select My String"
array = ["Yellow", "Green", "Blue", "Red"]
}
if identifier == "Int" {
title = "Select My Int"
array = [8, 16, 32, 64]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
if identifier == "String" {
cell.textLabel?.text = array[indexPath.row] as? String
cell.accessoryType = (array[indexPath.row] as String) == passedString ? .Checkmark : .None
}
if identifier == "Int" {
cell.textLabel?.text = "\(array[indexPath.row] as Int)"
cell.accessoryType = (array[indexPath.row] as Int) == passedInt ? .Checkmark : .None
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
for cell in tableView.visibleCells() as [UITableViewCell] {
cell.accessoryType = .None
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell!.accessoryType = .Checkmark
//Return the new value back to MasterViewController
var dict: [String : AnyObject]!
if identifier == "String" {
passedString = array[indexPath.row] as? String
dict = ["String" : array[indexPath.row] as String]
}
if identifier == "Int" {
passedInt = array[indexPath.row] as? Int
dict = ["Int" : array[indexPath.row] as Int]
}
NSNotificationCenter.defaultCenter().postNotificationName("attributeChange", object: nil, userInfo: dict)
}
}
This code works fine but I have a problem: I don't like it. It doesn't look like Swift style modern code, it looks like a copy-paste from good old Objective-C to Swift. I dislike the fact to have an identifier property in DetailViewController: I always have to check identifier in if statements in order to perform actions. I also dislike the fact to have passedString and passedInt properties with one of them being nil in half of the cases. And, worst of it, I dislike the fact that array is of type [Any]!: it leads to many downcastings.
Is there any better way to write this code? Swift provides tools like gerenic structs and classes or protocol conformance type arrays. Can't they help write more proficient code here?