iOS Swift - Show Contacts in TableView using UILocalizedIndexedCollation - ios

// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
print("titleForHeaderInSection: \(collation.sectionTitles[section])")
return collation.sectionTitles[section]
}
override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String] {
print("sectionIndexTitlesForTableView: \(collation.sectionIndexTitles)")
return collation.sectionIndexTitles
}
override func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
print("sectionForSectionIndexTitle: \(sections.count)")
return collation.sectionForSectionIndexTitleAtIndex(index)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (self.results.count > 0) ? self.results.count : 0
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = UILocalizedIndexedCollation.currentCollation().sectionTitles.count
print("numberOfSections: \(numberOfSections)")
return numberOfSections
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("contactscell") as UITableViewCell!
let label = cell.viewWithTag(1) as? UILabel
label?.text = self.results[indexPath.row].givenName
return cell
}
It Display all contacts in every sections. I want to show contacts in sorted order with alphabetical index a to z

You're returning self.results.count in numberOfRowsInSection regardless of which section you are in. You have to return the number of rows for each letter. Consider using a dictionary with letters as the keys and contacts as the values.

Related

Fatal error: Array index out of range in swift2 version

Please help with the error I have
on this line:
cell.name.text = names[indexPath.row] //error array index out of range
This is my declaration:
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var names = ["Anna","aanal"]
var petnames = ["Anu","aalu"]
#IBOutlet var tableView: UITableView!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.name.text = names[indexPath.row] //error array index out of range
cell.petname.text = petnames[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your array only has 2 elements while your numberOfRowsInSection method returns 3. Either change it to 2 or add 3 elements in your array
The ideal way is to change
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
But usually dont work with 2 arrays and create a Entity object having name and petname as elements and then have an array of your entity class to populate tableview
Try this :
I think your are passed petnames in numberOfRowsInSection and names and petnames count are also different so this problem occurs .
Solution
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if names.count == petnames.count{
return petnames.count
}
return 0;
}
OR
You have passed more numberOfRowsInSection then array.count
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2 or names.count
}
There are 2 values in your arrays names and petnames. However, there are 3 rows in your Table View. So, if the 3rd row of the table view is selected, it will be out of range of the array as there is no 3rd element in the arrays.
The solution is to make your names array and petnames array contain 3 elements:
var names = ["Anna","aanal", "boo"]
var petnames = ["Anu","aalu", "bo"]
or to return 2 rows in your table view:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
The best way is to return the count of the arrays (if the count of both arrays are different, return nothing):
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if names.count == petnames.count {
return names.count
}
return 0
}
Just pass the count of array
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArray.count
}
var names = ["Anna","aanal"] // you have 2 elemnts
var petnames = ["Anu","aalu"]
#IBOutlet var tableView: UITableView!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return 3 // you have returned 3 but it should be 2
// it should be
return 2
//or
// return names.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.name.text = names[indexPath.row] //you got error because you are trying to get 3 element from array where as there are only 2 elements
cell.petname.text = petnames[indexPath.row]
return cell
}
It is better if you use your arrayname.count

UITableView not showing all sections

I have a problem that I want to show a tableview, but separated in sections by the "status" of each item. I know how to do it with a simple string array, but I can't get to make this work with a class (Aluno) array, here's my code so far:
import UIKit
class DeliveriesTVC: UITableViewController {
let sections = ["Delivered", "Not Delivered"]
var studentList: [Array<Student>] = [[], []]
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...5{
studentList[0].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Delivered"))
}
for i in 6...10{
studentList[1].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Not Delivered"))
}
self.title = "Deliveries"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cellEntrega = tableView.dequeueReusableCell(withIdentifier: "EntregaCell", for: indexPath) as? EntregaCell {
let entregaCell = studentList[indexPath.section][indexPath.row]
// here i call a function in my TableViewCell class that update the cell itself
cellEntrega.updateAlunoUI(Aluno: entregaCell)
return cellEntrega
} else {
return UITableViewCell()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listaAlunos[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
}
In the output, i just get the "first section" showing, and without a name, even with me setting the name of each section and the number of sections. I've looked everywhere but i couldn't find a solution.
Your numberOfSections and titleForHeader methods are wrong, it should be
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
Additionally, you should return self.sections.count instead of return 2 in numberOfSections being hardcoded as in case you add another object to the array, you will have to change the 2 to whatever elements the array has now.
For your numberOfSectionInTableView function, shouldn't it be override func numberOfSectionsInTableView(in tableView: UITableView) -> Int {
return 2
} with a in in front of the tableView: UITableView?
I don't see where you connect your UITableView's delegate and datasource.
Here is a tutorial to show your about using UITableView.
Take a look at "Basic Table View" - "Step 3: Set the datasource and delegate"

index out of range in when we using multi-dimentional array

class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource {
var sections = ["A","B","C","D"]
var items = [["General","Privacy",""],["icloud","Maps","News"],["safari","Photos and Camera","Game Center"],["Twitter","Facebook","Flicker"]]
var secItems = ["iclouds","Maps","Safari"]
var thirItems = ["Twitter","General","Privacy","icloud"]
var imgItems = ["settings_ios7_ios_7.png","privacy.jpeg","icloud.png","Google-Maps-4.0-for-iOS-app-icon-small.png","news.jpeg","safari_ios7_ios_7 (1).png","photos.jpeg","game_center_ios7_ios_7.png","twitter.jpeg","facebook.jpeg","flicker.png"]
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Settings"
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "ABC"
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.lblName.text = items[indexPath.section][indexPath.row]
cell.imgName.image = UIImage(named: imgItems[indexPath.row])
cell.arrow.image = UIImage(named: "arrowIcon.png")
return cell
}
}
Getting error index out of range in here:
cell.lblName.text = items[indexPath.section][indexPath.row]
(when we take 4 by 4 multi-dimensional array it works fine, but we take different array it's getting index out of range.
In numberOfRowsInSection you are returning items.count which will be count of total array in your Item array... which is actually number of sections.count which is wrong. It should be items[section].count
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].count
}

TableView Controller -Swift

I'm trying to present an array of names into cells of tableview controller.
Here's the code:
import UIKit
class TableViewController: UITableViewController
{
var names = ["aA", "aB", "cC"]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return names.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath)
cell.detailTextLabel!.text = names[indexPath.row]
return cell
}
}
When I simulate it, nothing has appeared into the cells!
What's wrong with my Code!
The compiler did not give me any errors.
Update number of sections. Your problem will be solved.
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

How can I group TableView items from a dictionary in swift?

Lets consider this example:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier:"test")
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return ???
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return names.count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return ???
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return ????
}
}
let's assume that we need that the keys (fruits and vegetables) of the dictionary are the number of sections, plus they will be the titles of the sections. The items of the keys (eg apples and banana) will be the rows of each section. How can I implement this in my code? I know it might be easy but I couldn't figure it out my self.
You can use struct for that and here is example:
import UIKit
class TableViewController: UITableViewController {
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
struct Objects {
var sectionName : String!
var sectionObjects : [String]!
}
var objectArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
for (key, value) in names {
println("\(key) -> \(value)")
objectArray.append(Objects(sectionName: key, sectionObjects: value))
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return objectArray.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objectArray[section].sectionObjects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = objectArray[indexPath.section].sectionObjects[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return objectArray[section].sectionName
}
}
Swift 2
you dictionary example
var dic:Dictionary<String,String> = ["key":"value","key1":"value2"]
Your table
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
var key = Array(self.dic.keys)[indexPath.row]
var value = Array(self.dic.values)[indexPath.row]
cell.text = key + value
}
If you want it sorted use the global sorted function to sort the dictionary.
import UIKit
class TableViewController: UITableViewController {
var names = ["Vegetables": ["Tomato", "Potato", "Lettuce"], "Fruits": ["Apple", "Banana"]]
var namesSorted = [String, Array<String>]()
override func viewDidLoad() {
super.viewDidLoad()
// Sort names
namesSorted = sorted(names) { $0.0 < $1.0} // namesSorted = ["Fruits": ["Apple", "Banana"], "Vegetables": ["Tomato", "Potato", "Lettuce"]]
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return namesSorted.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesSorted[section].1.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = namesSorted[indexPath.section].1[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return namesSorted[section].0
}
}
All collection types must be Array
var names = [["Tomato", "Potato", "Lettuce"], ["Apple", "Banana"]]
var sectionNames = ["Vegetables", "Fruits"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names[section].count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return names.count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return sectionNames
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return sectionNames[section]
}
From Apple Documentation :
var keys: LazyForwardCollection<MapCollectionView<Dictionary<Key, Value>, Key>> { get }
Description: A collection containing just the keys of self. Keys appear in the same order as they occur as the .0 member of key-value pairs in self. Each key in the result has a unique value.
names.keys.array returns an Array of the keys.
SO:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names.keys.array[section].count
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return names.keys.array
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return names.keys.array[section]
}
This will work on Any Dictionary with any amount of data(even if it is unknown to the programmer
An easier way to solve this problem is to copy your dictionary into a temporary variable. Use removeFirst to extract the values from the array inside the dictionary.
var itemList=["Grocery":["soap","flour","carrots"],"Vehicles":["oil change","gas","tire rotation"],"Household":["Cable","Tv","cellphone"]]
var itemListTmp :[String:[String]] = [:]
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text=itemListTmp[keysItem[indexPath.section]]?.removeFirst()
//cell.textLabel?.text=itemList[indexPath.section].items[indexPath.row]
return cell
}
Another way of solving this problem is to extract keys and values in separate arrays:
var task=[String](itemList.keys)
var tobeDone=[[String]](itemList.values)
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return task[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text=tobeDone[indexPath.section][indexPath.row]
return cell
}
Similar to https://stackoverflow.com/a/31136537/11098567 answer I would use classes instead of structs, so that you can manipulate or add to your values after it has been placed into the array.
#objc func addToInitialClassInstance() {
let classInstance = Class(property1: String, property2: [CLass2.init(property1: String, property2: String)])
let isAvailable = initialClassInstance.contains { (classInArray) -> Bool in
if classInArray.property == classInstance.property {
classInArray.property2.append(classInstance.property2[0])
return true
}
return false
}
if !isAvailable {
initialClassInstance.append(classInstance)
}
tableView.reloadData()
}

Resources