0

Back in the old Objective-C days I would often use enums for things like tables with constant contents, segmented controls, etc - in situations where there was an enforced incremented list of integers starting at zero. I would also often add a ...count member at the end to give a count of the entries, useful for table section & rows. Trying to do this with swift enums is proving troublesome - lots of conversions to & from raw values and extra default clauses in switches to allow for the 'count' entry. Can anyone suggest a graceful method of dealing with these sorts of situations?

Rev. Andy
  • 81
  • 1
  • 5
  • if you want to count your entries, don't add this member, try this [How do I get the count of a Swift enum?](http://stackoverflow.com/questions/27094878/how-do-i-get-the-count-of-a-swift-enum) – Nazariy Vlizlo Jul 22 '15 at 08:42

2 Answers2

2

Automatic increment is still available in Swift.

enum Section: Int {
   case A = 0
   case B
   case C
}

Section.C.rawValue // -> 2

As for count, you should implement it manually (as How do I get the count of a Swift enum?):

enum Section: Int {
   case A = 0
   case B
   case C

   static let count = C.rawValue + 1
}

As for "conversions to & from raw values and extra default clauses" problem, compare with enum instead of its rawValue.

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return Section.count
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch Section(rawValue: section)! {
    case .A: return 1
    case .B: return 2
    case .C: return 5
    }
}

If you want to do something like array[Section.A], you can easily implement it.

extension Array {
    subscript(section: Section) -> T {
        return self[section.rawValue]
    }
}

extension NSIndexPath {
    convenience init(forRow row: Int, inSection section: Section) {
        self.init(forRow: row, inSection: section.rawValue)
    }
}

let array = ["foo", "bar", "baz"]
array[.B] // -> "bar"


let indexPath = NSIndexPath(forRow: 20, inSection: .C)
indexPath.section // -> 2
indexPath.row // -> 20

And so on.. :)

Community
  • 1
  • 1
rintaro
  • 51,423
  • 14
  • 131
  • 139
  • Hard-coding the count - either as a literal or by referencing the (named) last element - are maintenance issues waiting to happen, the whole point of the ...count member was to automate this process. The best solution seems to be to add a 'count' computed value that iterates through integers from zero until it finds one that isn't a valid raw value. Which is clunky but usable. – Rev. Andy Jul 23 '15 at 15:50
  • You don't need to make `count` a computed value. for exmaple: `static let count: Int = { var i = 0; while Section(rawValue: i) != nil { i++ }; return i }()` works. – rintaro Jul 24 '15 at 07:30
0

Add a function "count" to each enum. For example

static func count() -> Int { return 3 }

Integer -> enum conversion is done by the init method.

gnasher729
  • 51,477
  • 5
  • 75
  • 98