StuartM StuartM - 3 months ago 147
Swift Question

Adding section index headers for A to Z UITableView scrolling

I am trying to add some section headers for a contacts table view. I have a list of contacts in an

Array
which might be like this:

Bill Apple

Borat

Steve Test

I have added the following:

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
let sectionTitles = currentCollation.sectionTitles as NSArray
return sectionTitles.objectAtIndex(section) as? String
}

func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
return currentCollation.sectionIndexTitles as [String]
}

func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
return currentCollation.sectionForSectionIndexTitleAtIndex(index)
}


This gets the A-Z headings to show up. However as there is only one section and one array holding the contacts the actual functionality does not work.

Should we be sorting the
Array
into an alphabetised
Array
in some sort? So that it has multiple sections? Or is there an easier way to approach this?

Answer

Should we be sorting the Array into an alphabetised Array in some sort? So that it has multiple sections?

Yes.

You added the delegate methods for the section index, but you didn't show any code that actually performed the collation.

Here's some sample code from NSHipster showing how to use UILocalizedIndexedCollation to collate an array of objects (e.g., contacts) into an array of sections of objects (e.g., contacts grouped by section):

let collation = UILocalizedIndexedCollation.currentCollation()
var sections: [[AnyObject]] = []
var objects: [AnyObject] = [] {
    didSet {
        let selector: Selector = "localizedTitle"
        sections = Array(count: collation.sectionTitles.count, repeatedValue: [])

        let sortedObjects = collation.sortedArrayFromArray(objects, collationStringSelector: selector)
        for object in sortedObjects {
            let sectionNumber = collation.sectionForObject(object, collationStringSelector: selector)
            sections[sectionNumber].append(object)
        }

        self.tableView.reloadData()
    }
}

You'll also want to update your remaining tableView delegates to use the sections array:

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

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let contact = sections[indexPath.section][indexPath.row]
    ...
} 

FYI, you can simplify your delegate code by assigning the collation property to your view controller, instead of repeatedly declaring a local variable for the (current) collation inside each delegate method. For example:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
    return collation.sectionTitles[section]
}