Can't present data in table view cell - ios

I am trying to retrive each row from database and keep value in dictionary. After that I have created a array of dictionary. But when i am trying to show each value of dictionary in table cell, i can't . Here is my code
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var borrowerInformation:NSMutableDictionary? = NSMutableDictionary();
var borrowerName:String = ""
var givenDate:String = ""
var borrower:NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
dataQuery()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.borrower.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! BorrowerLanderTableViewCell
cell.borrowerName.text = self.borrower[indexPath.row] as? String
return cell
}
func dataQuery(){
let queryBorrower = PFQuery(className:"BorrowerLander")
queryBorrower.whereKey("borrowerLander", equalTo: 0)
queryBorrower.whereKey("userId", equalTo: (PFUser.currentUser()?.objectId)!)
queryBorrower.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
self.borrower = NSMutableArray()
if error == nil {
if let borrowerData = objects {
for object in borrowerData {
self.borrowerName = object["name"] as! String
self.givenDate = object["givenDate"] as! String
self.borrowerInformation = [ "borrowerName": self.borrowerName,"givenDate":"self.givenDate"]
self.borrower.addObject(self.borrowerInformation!)
}
}
}
self.tableview.reloadData()
}
}
}
Here, i have just added main part of the code. Please tell me how can i show value of array of the dictionary in table view cell?

I don't know how you did the setup but an issue could be that you have not set your tableviews delegate and datasource to the controller you are working with.
self.tableView.dataSource = self
self.tableView.delegate = self
I'm also wondering if you did implement the numberOfRows and numberOfSections delegate methods.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return borrower.count
}
and
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
Also when setting the text you need to actually use the name string you added to the dictionary
let borrower = self.borrower[indexPath.row]
if let name = borrower["borrowerName"] as? String{
cell.borrowerName.text = name
} esle {
cell.borrowerName.text = "error"
}
Also declare your data array as
var borrower:[[String: AnyObject]] = []
Extra edit:
I do want to say that I really think you should use a custom object here instead of an dictionary
class Borrower {
var name: String
var givenDate: String
//etc.
init(name: String, givenDate: String) {
self.name = name
self.givenDate = givenDate
}
}
enabling the following
var borrower:[Borrower] = []
and in the query:
for object in borrowerData {
if let name = object["name"] as? String, givenDate = object["givenDate"] as? String {
self.borrower.append(Borrower(name: name, givenDate: giverDate))
}
}

First, make sure you've set the dataSource and delegate for your table view to your view controller. Then, the function tableView:cellForRowAtIndexPath: will never get called unless you implement tableView:numberOfRowsInSection. The default implementation of that function returns 0. Try implementing this:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return borrower.count
}
Also, if the code inside of queryBorrower.findObjectsInBackgroundWithBlock { is actually in the background, you need to dispatch your table view reload to the main thread. Like this:
dispatch_async(dispatch_get_main_queue(), { [weak self] () -> Void in
self?.tableView.reloadData()
})

You need to implement numberOf... dataSource delegate first:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int

Related

empty tableview cell for at index path row is not called

All the tableview functions are working except cell for row index path .
The problem maybe that foods array is empty so the number for rows is 0 so the cell for row at index path is not called
#IBOutlet weak var foooods: UITableView!
var databaseref = Database.database().reference()
var img : AnyObject?
var foods = [String?]()
override func viewDidLoad() {
super.viewDidLoad()
self.databaseref.child("basic food").observe(.childAdded, with: {( snap: DataSnapshot) in
let snapp = snap.value as! [String:AnyObject]
if let x = snapp["name"] as! String? {
self.foods.insert(x, at: 0)
//self.foods.append(x)
}
})
self.foooods.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.foods.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("difufuehf")
let cell : foodsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "aupa", for:indexPath) as! foodsTableViewCell
print("fufvksdfvysdgfvjdsgfdsygfvds,jhvjsdvsdjvguydsfgdsylfgdsyfgsdlygfsiygf")
if let foo = foods[indexPath.row] {
print(foo)
cell.food.text = foo
}
return cell
}
This must be a duplicate but I can't find one.
Your issue is that you call reloadData in the wrong place which results in it being called far too soon. You need to call it inside the completion block, after you update your data model.
And you need to make sure it gets called on the main queue.
override func viewDidLoad() {
super.viewDidLoad()
self.databaseref.child("basic food").observe(.childAdded, with: {( snap: DataSnapshot) in
if let snapp = snap.value as? [String:Any], let x = snapp["name"] as? String {
self.foods.insert(x, at: 0)
//self.foods.append(x)
DispatchQueue.main.async {
self.foooods.reloadData()
}
}
})
}
Note that I also fixed the way the value is obtained. You really need to avoid force unwrapping and force casting.

Want indexed tableview with reference back to source array

In iOS/Swift I've created an indexed "client" UITableView based on the clientName property in my Client class. I created a dictionary with A to Z as the sections. The indexed tableview works great. However, I'm trying to figure out a way to determine which row it is in the original source array, when the user selects a row. I was thinking of building some type of cross reference array, except that the dictionary ends up sorted to match the sections, so I don't know which section/row combo matches which original array entry. Is there a common approach to handling this issue?
In an attempt to clarify...
class Client {
var clientId : Int!
var firstName : String!
var lastName : String!
var email : String!
var phone : String!
...
init() {
}
}
var clients: [Client] = []
// clients array loaded from web service
...
// Create dictionary to be source for indexed tableview
func createClientDict() {
clientDict = [String: [String]]()
clientSectionTitles = [String]()
var clientNames:[String] = []
for i in 0..<clients.count {
let client = clients[i]
let clientName = "\(client.lastName), \(client.firstName)"
clientNames.append(clientName)
}
for name in clientNames {
var client: Client = Client()
// Get the first letter of the name and build the dictionary
let clientKey = name.substringToIndex(name.startIndex.advancedBy(1))
if var clientValues = clientDict[clientKey] {
clientValues.append(name)
clientDict[clientKey] = clientValues
} else {
clientDict[clientKey] = [name]
}
}
// Get the section titles from the dictionary's keys and sort them in ascending order
clientSectionTitles = [String](clientDict.keys)
clientSectionTitles = clientSectionTitles.sort { $0 < $1 }
}
Now, when the user taps a row in the tableview, I can get the section and row (indexPath). However, how can I determine which row in the clients array is the match, assuming there could be duplicate names? Is there some way to create a cross reference of indexed section/row mapped to row in source array on the fly? I was going to try to do that while building the dictionary, except that the dictionary gets sorted after, so nothing would match up. Maybe I should somehow be including the source row number in/with the dictionary??
Here is the tableview code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ClientCell
let clientKey = clientSectionTitles[indexPath.section]
if let clientValues = clientDict[clientKey] {
cell.clientName.text = clientValues[indexPath.row]
}
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return clientSectionTitles.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let clientKey = clientSectionTitles[section]
if let clientValues = clientDict[clientKey] {
return clientValues.count
}
return 0
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return clientSectionTitles[section]
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return clientIndexTitles
}
func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
guard let index = clientSectionTitles.indexOf(title) else {
return -1
}
return index
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20
}
func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let headerView = view as! UITableViewHeaderFooterView
headerView.contentView.backgroundColor = UIColor ( red: 0.0, green: 0.3294, blue: 0.6392, alpha: 1.0 )
headerView.textLabel?.textColor = UIColor.greenColor()
headerView.textLabel?.font = UIFont(name: "Noteworthy-bold", size: 15.0)
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedIndex = indexPath
// In the following prepare for segue, I need to somehow use the selected indexpath to find the correct entry
// in the clients array and pass it along.
performSegueWithIdentifier("clientDetailSegue", sender: self)
}
I figured it out. I didn't realize (until I recently tried it) that you could nest an array of any class in a dictionary. When I changed my dictionary to have my clients array nested in it, all was solved. I changed my function as shown below.
func createClientDict() {
// Declared for view controller. Re-initialized here.
clientDict = [String: [Client]]()
clientSectionTitles = [String]()
clients.sortInPlace ({ $0.lastName < $1.lastName })
for c in clients {
let clientName = "\(c.lastName), \(c.firstName)"
// Get the first letter of the name and build the dictionary
let clientKey = clientName!.substringToIndex(clientName!.startIndex.advancedBy(1))
if var clientValues = clientDict[clientKey] {
clientValues.append(c)
clientDict[clientKey] = clientValues
} else {
clientDict[clientKey] = [c]
}
}
// Get the section titles from the dictionary's keys and sort them in ascending order
clientSectionTitles = [String](clientDict.keys)
clientSectionTitles = clientSectionTitles.sort { $0 < $1 }
}
However, this line was the key to the solution:
let clientDict = [String: [Client]]()

Slow/Stuttered scroll in tableview

I'm loading about 150 elements from an array of arrays of dictionaries (tasks) and I can get all of the data into my tableview but when I scroll its stupid slow. When I print out the information of one of my functions to the console, it looks like I am getting all of the data back every time I scroll. Is this something I am not loading well (i.e. asynchronously) or do I need to change my functions?
func querySections() -> [String] {
var sectionsArray = [String]()
for task in tasks {
let dueTimes = task.dueTime
sectionsArray.append(dueTimes)
}
let uniqueSectionsArray = Array(Set(sectionsArray.sort()))
// print(uniqueSectionsArray)
return uniqueSectionsArray
}
func queryDueTimes(section:Int) -> [Task] {
var sectionItems = [Task]()
for task in tasks {
let dueTimes = task.dueTime
if dueTimes == querySections()[section] {
sectionItems.append(task)
}
}
print(sectionItems)
return sectionItems
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return querySections()[section]
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return querySections().count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return queryDueTimes(section).count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell
// Configure the cell...
cell.selectionStyle = .None
let times = queryDueTimes(indexPath.section)
let task = times[indexPath.row]
cell.label.text = task.title
if task.done == true {
cell.checkBox.image = UIImage(named: "checkedbox")
cell.detailLabel.text = "Completed By: \(task.completedBy)"
}
else {
cell.checkBox.image = UIImage(named: "uncheckedbox")
cell.detailLabel.text = ""
}
cell.delegate = self
return cell
}
Basically, in querySections, I'm iterating through all of the dueTimes for each task and then changing them into an array of a set so I can filter out all of the duplicates. This is giving me all of my sections. For queryDueTimes, I'm iterating through the tasks and matching them to a section.
I had a thought about calling the functions in viewDidLoad but that isn't working (it keeps giving me an empty array when I try to pass it to another empty array thats more accessible outside of the function) and I can't access section (for queryDueTimes) in viewDidLoad (as far as what I know how to do).
Update 1:
I think the mistake is on my end. I said that I tasks is an array of arrays when its just an array of Tasks (a struct with all of the properties of each task). When I load the app, I append all of the tasks from my backend to a local array ("tasks"). Should I have an array of arrays for this to work or can I amend my code somehow and get it to work?
Update 2:
I'm getting sectionTimes and tasksInSectionArray as empty arrays when I print them.
var sectionTimes = [String]()
var tasksInSectionArray = [[Task]]()
var tasks = [Task]() {
didSet {
tableView?.reloadData()
}
}
func updateTableView() {
sectionTimes = Set(tasks.map{$0.dueTime}).sort()
tasksInSectionArray = sectionTimes.map{section in tasks.filter{$0.dueTime == section}}
print(sectionTimes)
print(tasksInSectionArray)
tableView.reloadData()
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTimes[section]
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionTimes.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasksInSectionArray[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell
// Configure the cell...
cell.selectionStyle = .None
let task = tasksInSectionArray[indexPath.section][indexPath.row]
Like you guessed, the data is being loaded and sorted over and over again, instead of only once. Save the results of querySelections and queryDueTimes and use that inside the table view data source methods.
You can do this in viewDidLoad - call both functions once and assign the results to a variable at the class level, and then call tableView.reloadData() (assuming you have a reference to the table view).
var sections: [String] = []
var data: [[Tasks]] = []
func updateTableView() {
sections = Set(tasks.map { $0.dueTime }).sort()
data = sections.map { section in tasks.filter { $0.dueTime == section } }
tableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let task = data[indexPath.section][indexPath.row]
// Cell configuration
}
This is basically what DMan said, but I've made an example for you.

Populating user image and text posts, compiles and runs but cells are empty. Parse Swift

I am trying to populate my feed of images and text users post. The code compiles and runs but I get empty cells.
var titles = [String]()
var locations = [String]()
var dates = [String]()
var imageFiles = [PFFile]()
override func viewDidLoad() {
super.viewDidLoad()
var privacySettingQuery = PFQuery(className: "Posts")
privacySettingQuery.whereKey("privacy", equalTo: true)
privacySettingQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.titles.append(object["name"] as! String)
self.dates.append(object["dateTime"] as! String)
self.locations.append(object["location"] as! String)
self.imageFiles.append(object["imageFile"] as! PFFile)
}
}
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return titles.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell {
let postsCell = tableView.dequeueReusableCellWithIdentifier("PostsCell", forIndexPath: indexPath) as! PostsCell
postsCell.postImage.image = UIImage(named: "Post-Image- Placeholder-1.png")
postsCell.postTitle.text = titles[indexPath.row]
postsCell.postLocation.text = locations[indexPath.row]
postsCell.postDate.text = dates[indexPath.row]
return postsCell
}
Any help would be appreciated. Also is there a better way to do this other than using arrays?
To solve the empty issue.You need call tableView.reloadData() after you got the objects.
Model class like
class Post: NSObject {
var title: String
var location: String
var date: NSDate
var imageFile: PFFile
}
And in viewController use
var posts: [Post]?
instead of the 4 arrays
When this code is being called
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return titles.count
}
The value for titles.count is still 0. After you finish fetching the info from parse and you have values for the arrays you must reload the UITableView. To do this make an outlet for the UITableView and call it tableView. Then call this code tableView.reloadData()
Hope this helps!!

Add an Index to a searchBar

Need help to correct this code. I have a coredata app with restaurant names and address, have a search Bar and it is working. What I want to add is a Index and a IndexTitle as showed in the picture below (arrows). Any help is more than welcome. Thanks in advance.
import UIKit
import CoreData
class DictionaryTableViewController: UITableViewController, NSFetchedResultsControllerDelegate, UISearchResultsUpdating
{
var searchController:UISearchController!
var searchResults:[Dictionary] = []
private var dictionaryItems:[Dictionary] = []
var fetchResultController:NSFetchedResultsController!
override func viewDidLoad() {
super.viewDidLoad()
if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext {
let fetchRequest = NSFetchRequest(entityName: "DictionaryEntity")
do {
dictionaryItems = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Dictionary]
} catch {
print("Failed to retrieve record")
print(error)
}
}
searchController = UISearchController(searchResultsController: nil)
tableView.tableHeaderView = searchController.searchBar
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
tableView.estimatedRowHeight = 30.0
tableView.rowHeight = UITableViewAutomaticDimension
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 26
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.active {
return searchResults.count
} else {
return dictionaryItems.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DictionaryTableViewCell
// Configure the cell...
cell.wordLabel.text = dictionaryItems[indexPath.row].word
cell.definitionSmallLabel.text = dictionaryItems[indexPath.row].definition
let dictionary = (searchController.active) ? searchResults[indexPath.row]: dictionaryItems[indexPath.row]
// Configure the cell...
cell.wordLabel.text = dictionary.word
cell.definitionSmallLabel.text = dictionary.definition
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
return "dictionaryItems\(section)"
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
if searchController.active{
return false
}else{
return true
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDictionaryDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = segue.destinationViewController as! DictionaryDetailViewController
destinationController.dictionary = (searchController.active) ? searchResults[indexPath.row] : dictionaryItems[indexPath.row]
searchController.active = false
}
}
}
func updateSearchResultsForSearchController(searchController:
UISearchController) {
if let searchText = searchController.searchBar.text {
filterContentForSearchText(searchText)
tableView.reloadData()
}
}
func filterContentForSearchText(searchText: String) {
searchResults = dictionaryItems.filter({ (dictionary:Dictionary) -> Bool in
let wordMatch = dictionary.word!.rangeOfString(searchText, options:
NSStringCompareOptions.CaseInsensitiveSearch)
return wordMatch != nil
})
}
}
What I am trying to have in my table View is the Index (Arrows in the left) and the Index Title (Arrows in the right side).
You have typos in your override function for titleForHeaderInSection
Here is the corrected one, note that v in tableView is capital: (copy paste my code)
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
}
I'd recommend using the auto-complete feature of Xcode. that way, you don't get stuck in insidious errors like this.
UPDATE:
You also need to provide both of these methods to see section header and section index titles.
override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return ["A", "B", "C"]
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "A title for section: \(section)"
}
Try the following code:
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 9
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 9
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel?.text = "\(indexPath.section+1)\(indexPath.row+1)"
return cell
}
override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return ["A", "C", "B"]
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "SECTION \(section+1)"
}
}
One way to do this is using built-in properties on the NSFetchedResultsController. The most important part of this is setting up the sectionNameKeyPath (which should be the managed object attribute holding the title).
private var frc: NSFetchedResultsController? = nil
private lazy var fetchedResultsController:NSFetchedResultsController = {
if self.frc != nil {
return self.frc!
}
//grab your managed object context
let moc = dbStore.sharedInstance.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Transaction")
fetchRequest.fetchBatchSize = 30
fetchRequest.resultType = NSFetchRequestResultType.ManagedObjectResultType
let sortDescriptorByTimeStamp = NSSortDescriptor(key: "timeStamp", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptorByTimeStamp]
//in-memory cache when cachename is nil, delegate is non-nil
//note the sectionNameKeyPath requires that I have a related category object with the categoryName attribute on my Transaction managed object
let nfrc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: "category.categoryName", cacheName: nil)
self.frc = nfrc
do
{
try self.frc!.performFetch()
} catch let e as NSError {
fatalError(e.localizedDescription)
}
return self.frc!
}()
Section Titles
To get the section titles you implement this method.
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let sectionTitle = self.fetchedResultsController.sections?[section].name ?? "No Category Titles"
return sectionTitle
}
Table Index
To setup the index you implement the following method.
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return self.fetchedResultsController.sectionIndexTitles ?? [""]
}
Note the Quick Help Documentation when you click on
sectionIndexTitles. The array of section index titles. The default
implementation returns the array created by calling
sectionIndexTitleForSectionName: on all the known sections. You should
override this method if you want to return a different array for the
section index. You only need this method if you use a section index.
Source
If you want to see this in context, to get the gist of how to use the NSFetchedResultsController in this way you can checkout my sample at this location.
Alternates (Arrays/Dictionaries)
There are a few other tutorials about how to build an index from arrays and dictionaries (but I recommend the method above as simplest way to proceed).
Alternate Tutorial #1
Alternate Tutorial #2
Alternate Implementation
Note: Code in this section is from Alternate Tutorial #1
// `UIKit` convenience class for sectioning a table
let collation = UILocalizedIndexedCollation.currentCollation()
as UILocalizedIndexedCollation
....
/* section headers
appear above each `UITableView` section */
override func tableView(tableView: UITableView,
titleForHeaderInSection section: Int)
-> String {
// do not display empty `Section`s
if !self.sections[section].users.isEmpty {
return self.collation.sectionTitles[section] as String
}
return ""
}
/* section index titles
displayed to the right of the `UITableView` */
override func sectionIndexTitlesForTableView(tableView: UITableView)
-> [AnyObject] {
return self.collation.sectionIndexTitles
}
override func tableView(tableView: UITableView,
sectionForSectionIndexTitle title: String,
atIndex index: Int)
-> Int {
return self.collation.sectionForSectionIndexTitleAtIndex(index)
}

Resources