How to display data in table view in swift 3? - ios

Here I need to pass the data to the table view to display and getting lots of errors can anyone help me how to implement this here keys should be displayed as section header title and inside values should be displayed in rows
Here is the declaration for the array
var finalDict = [String: [String]]()
the output of the array is shown below
["Flat Rate": ["Fixed", "Base", "Fixed two"], "Best Way": ["Worldwide Express Saver one", "Table Rate", "Worldwide Expedited", "Worldwide Express Saver"]]
Here is the code for table view
func numberOfSections(in tableView: UITableView) -> Int {
return finalDict.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let names = self.finalDict.keys
return names[section]
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.tintColor = UIColor.white
header.textLabel?.textColor = UIColor.darkGray
header.textLabel?.textAlignment = NSTextAlignment.left
header.textLabel?.font = UIFont(name: "Futura", size: 17)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let names = self.finalDict.keys
let a :[Any] = finalDict[names] as! [Any]
return a.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "shippingCell", for: indexPath) as! ShippingMethodTableViewCell
let key = self.keys[indexPath.section]
progressIcon.stopAnimating()
progressIcon.hidesWhenStopped = true
var a :[Any] = arrayss[key] as! [Any]
var dictionary = a[indexPath.row] as! [String:Any]
let price = dictionary ["price"]
let name = dictionary["name"]
let namePrice = "\(name!)" + " \(price!)"
cell.methodLabel.text = namePrice
cell.radioButton.addTarget(self, action: #selector(paymentRadioAction(button:)), for: .touchUpInside)
if chekIndex == indexPath {
cell.radioButton.isSelected = true
} else {
cell.radioButton.isSelected = false
}
return cell
}

For starters, update the following datasource methods
func numberOfSections(in tableView: UITableView) -> Int {
return finalDict.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let titles = Array(finalDict.keys)
return titles[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let titles = Array(finalDict.keys)
let currentTitle = titles[section]
let values = finalDict[currentTitle] as! [String]
return values.count
}

Please try to replace self.finalDict.keys with Array(self.finalDict.keys) .

Related

How to display tableview sections with API Model data Arrays

Here I want to display these data into two sections in my table view, I have the following arrays from the model.
Here I getting entire data into a single model and both are visible at the top.
var TotalbooksList : [BooksList]!
var RecomendBooks : [BooksList]!
var tableData: [(title: String, list: [BooksList]?)] {
return [(title: "Recomended Books", list: RecomendBooks),
(title: "Total Books", list: TotalbooksList)]
}
I write following Delegate Methods but I don't get data into a second section
func numberOfSections(in tableView: UITableView) -> Int {
return self.tableData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData[section].list?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RecomandBookTVCell", for: indexPath)as!RecomandBookTVCell
if let data = self.tableData[indexPath.section].list, data.count > 0 {
let model = data[indexPath.row]
cell.selectionStyle = .none
cell.booktitle.text = model.title ?? ""
cell.bookAuthor.text = model.author ?? ""
if model.photo != ""{
cell.bookimage.sd_setImage(with: URL(string: Services.BaseURL + (model.photo ?? "")), placeholderImage: UIImage(named: ""))
}
cell.genrelbl.text = model.genre ?? ""
cell.addlog.tag = indexPath.row
cell.addlog.addTarget(self, action: #selector(addLog(sender:)), for: .touchUpInside)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
tableData[section].title
}
You are returning wrong value in numberOfRowsInSection method else condition
And you are using TotalbooksList array for section 0 in numberOfRowsInSection method and using RecomendBooks array for section 0 in cellForRow method. Change it to use proper array.
class ViewController: UIViewController {
var totalbooksList: [BooksList]!
var recomendBooks: [BooksList]!
var tableData: [(title: String, list: [BooksList]?)] {
return [(title: "Recomended Books", list: totalbooksList),
(title: "Total Books", list: recomendBooks)]
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.tableData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData[section].list?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RecomandBookTVCell", for: indexPath) as! RecomandBookTVCell
if let data = self.tableData[indexPath.section].list, data.count > 0 {
let model = data[indexPath.row]
cell.selectionStyle = .none
cell.booktitle.text = model.title ?? ""
cell.bookAuthor.text = model.author ?? ""
if model.photo != ""{
cell.bookimage.sd_setImage(with: URL(string: Services.BaseURL + (model.photo ?? "")), placeholderImage: UIImage(named: ""))
}
cell.genrelbl.text = model.genre ?? ""
cell.addlog.tag = indexPath.row
cell.addlog.addTarget(self, action: #selector(addLog(sender:)), for: .touchUpInside)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
tableData[section].title
}
}

dictionary for tableView datasource

I am trying to use a dictionary for a tableView datasource, I am getting an object back from the database that contains a key and an array of values, so a [String: [String]]
var requestedList = [String]()
var keyArr = [String]()
var requestedDictionary = [String: [String]]()
let tQuery = PFQuery(className: "MyClass")
tQuery.whereKey("username", equalTo: PFUser.current()?.username as Any)
tQuery.selectKeys(["descContent", "header"])
do {
let returnedObjects = try tQuery.findObjects()
for object in returnedObjects {
let header = object["header"] as! String
keyArr.append(header)
if let arr = object["descContent"] as! [String]? {
requestedDictionary[header] = arr
requestedList += arr
}
}
} catch {
}
I can't seem to correspond the values correctly to the rows of the tableView however, I was suggested to use an array to store the values which is what I have done with the keyArr. My problem is how do I access the contents of the keys and the corresponding values in the datasource methods?? This is what I have so far but I haven't been able to link the keys and values accordingly
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return requestedList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RequestViewCell", for: indexPath) as! RequestViewCell
cell.descLbl.text = "Your ticket has been requested by \(requestedList[indexPath.row])"
cell.refLbl.text = "for: \(keyArr[indexPath.row])"
cell.leftBtn.tag = (indexPath.section * 100) + indexPath.row
cell.leftBtn.addTarget(self, action: #selector(leftClick(sender:)), for: .touchUpInside)
cell.rightBtn.tag = (indexPath.section * 100) + indexPath.row
cell.rightBtn.addTarget(self, action: #selector(rightClick(sender:)), for: .touchUpInside)
return cell
}
You can turn dictionary into tableView representable data this way.
let requestedDictionary:[String: [String]] = [
"Key-1":["Value-1","Value-2","Value-3","Value-4"],
"Key-A":["Value-X","Value-Y","Value-Z"],
"Key-a":["Value-x","Value-y"],
]
lazy var data:[(key:String,values:[String])] = requestedDictionary.compactMap({(key:$0,values:$1)})
func numberOfSections(in tableView: UITableView) -> Int {
data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].values.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = data[indexPath.section].values[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return data[section].key
}
Hope it helps.

Expandable Tableview work with sectionHeader

I am trying to load my different controller using Expandable Tableview but my headerview is set
as switch condition
For Header XXX1 -> two sub menu a and b ..
For Header XXX2-> sub menu c
but for Header XXX3 no sub menu ,, So i will work on click with XXX3(currently working with check SectionData.count == 0 ) but for multiple how to manage .. check out my code
sectionNames = ["xxxx1","xxxx2","xxx3","xxxx4"] //this is main header
sectionItems = [ ["a","b"],[c],[],[],[],[],[],[]]// This is sub menu items
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.expandedSectionHeaderNumber == section) {
let arrayOfItems = self.sectionItems[section] as! NSArray
return arrayOfItems.count;
} else {
return 0;
}
//return arraylist.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (self.sectionNames.count != 0) {
return self.sectionNames[section] as? String
}
return ""
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60.0;
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let section = self.sectionItems[indexPath.section] as! NSArray
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = section[indexPath.row] as? String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
}
let indexPath = tableView.indexPathForSelectedRow
// print(indexPath as Any)
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
// print(currentCell as Any)
//getting the text of that cell
let currentItem = currentCell.textLabel!.text
print(currentItem!)
switch currentItem {
case "XXXX1":
//// Here unable to do any work
break
case "a":
APICalla()
case "b":
APICallb ()
default:
break
}
return
}
Using this link
Sorry this tutorial is quite poor.
Swift is an object oriented language so use a custom model, a generic Section object with name, items and the information if the section is collapsed
class Section<T> {
var name : String
var items = [T]()
var isCollapsed = false
init(name : String, items : [T] = []) {
self.name = name
self.items = items
}
}
and a suitable struct for the items with a title and a closure to be called in didSelect
struct Item {
let title : String
let selectorClosure : (() -> Void)?
}
Rather than using multiple arrays populate the data source array consistently
var sections = [Section<Item>(name:"xxxx1", items: [Item(title: "a", selectorClosure: APICalla), Item(title: "b", selectorClosure: APICallb)]),
Section<Item>(name:"xxxx2", items: [Item(title: "c", selectorClosure: APICallc)]),
Section<Item>(name:"xxxx3")]
In numberOfRowsInSection return the proper number of items depending on isCollapsed
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let currentSection = sections[section]
return (currentSection.isCollapsed) ? 0 : currentSection.items.count
}
In cellForRow don't use typeless Foundation collection types
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let item = sections[indexPath.section].items[indexPath.row]
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = item.title
return cell
}
In the method to collapse/expand the sections just toggle isCollapsed
let currentSection = sections[section]
currentSection.isCollapsed.toggle()
and perform the animation
titleForHeaderInSection is much simpler, too
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].name
}
In didSelectRow never get any data from the view (the cell) get it from the model (the data source array) and call the selector closure. With this logic a switch is not needed.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
let item = sections[indexPath.section].items[indexPath.row]
item.selectorClosure?()
}
Swift4 I think this will helps you
// declare globally
var isExpanded : Bool = true
var indexOfSection = Int()
var yourArray = [ModelName]()
override func viewDidLoad() {
super.viewDidLoad()
indexOfSection = 999
}
extension ViewController: UITableViewDelegate, UITableViewDataSource
{
func numberOfSections(in tableView: UITableView) -> Int {
if yourArray.count > 0{
return yourArray.count
}else{
return 0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: view.frame.origin.x,y: 0 , width: view.frame.size.width ,height: 60))
headerView.backgroundColor = .white
let collapseBtn = UIButton(frame: CGRect(x: headerView.frame.origin.x,y: headerView.frame.origin.y , width: view.frame.size.width ,height: 60))
collapseBtn.addTarget(self, action: #selector(expandSection(sender:)), for: .touchUpInside)
collapseBtn.tag = section
collapseBtn.backgroundColor = .clear
headerView.addSubview(collapseBtn)
return headerView
}
#objc func expandSection(sender:UIButton){
print(sender.tag)
if isExpanded == true{
indexOfSection = sender.tag
mIdeaTableView.reloadData()
isExpanded = false
mTableView.reloadSections([indexOfSection], with: UITableView.RowAnimation.bottom)
}else{
indexOfSection = 999
isExpanded = true
self.mTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if yourArray.count > 0{
if yourArray[section].items!.count > 0{
if indexOfSection == section{
return yourArray[section].items!.count
}else{
return 0
}
}else{
return 0
}
}else{
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: “CellID”, for: indexPath) as! Cell
if yourArray[indexPath.section]. items!.count > 0{
if yourArray[indexPath.section]. items!.count > 0{
let ideas = yourArray[indexPath.section].ideaItems
if ideas!.count > 0{
if indexOfSection == indexPath.section{
cell.mLbl.text = ideas![indexPath.row].name ?? ""
if ideas![indexPath.row].isExpanded == true{
cell.mAddImg.image = #imageLiteral(resourceName: "tick")
}else{
cell.mAddImg.image = #imageLiteral(resourceName: "edit213-1")
}
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
//Structure of my response
{
items = (
{
name = “a”;
},
{
name = “b”;
},
);
name = “xxxx1”;
}
items = (
{
name = “c”;
},
);
name = “xxxx2”;
}
}

Duplicated values in grouped section UITableView swift IOS

I have created grouped sections in UITableView but values are getting duplicate. How to populate items under each section? Sections I already created. Few Title items are null.
SectionList --> Title --> Items
Like:
Bir have one item
Proj Plan have null item
Proj Ev has three items
I want to display textField in every section Title.
code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.dataSource = self
tableView.delegate = self
if let url = Bundle.main.url(forResource: "AppD", withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(AppointmentDetail.self, from: data)
self.AppData = jsonData
self.tableView.reloadData()
} catch {
print("error:\(error)")
}
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return AppData?.sectionList?[section].title
}
func numberOfSections(in tableView: UITableView) -> Int {
return AppData?.sectionList?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return AppData?.sectionList?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
// Configure the cell...
if let sections = AppData?.sectionList?[indexPath.section].items {
for item in sections {
if item.textField != "" {
cell.textLabel?.text = item.textField
}
}
}
Make changes as below
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return AppData?.sectionList?[section].items?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
cell.textLabel?.text = AppData?.sectionList?[indexPath.section].items?[indexPath.row].textField
cell.textLabel?.sizeToFit()
cell.textLabel?.numberOfLines = 0
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
For Adding HeaderView XIB to table view
var tableHeaderViewObj : BookNowHotelDetailHeader?
inViewdidload
tableHeaderViewObj = BookNowHotelDetailHeader(frame: CGRect(x: 0.0, y: 0.0, width: (window?.frame.width)!, height: 350))
self.BookNowTV.tableHeaderView = tableHeaderViewObj
tableHeaderViewObj?.parentVC = self
tableHeaderViewObj?.UpdateBookNowHotelData(Obj: hotelDetailObj ?? HotelDetailModal())

Alphabetical sections in table table view in swift

I have a list of names sorted alphabetically, and now I want display these names in a table view. I'm struggling with grouping these names for each letter.
My code looks like this:
let sections:Array<AnyObject> = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
var usernames = [String]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cellID = "cell"
let cell: UITableViewCell = self.tv.dequeueReusableCellWithIdentifier(cellID) as UITableViewCell
cell.textLabel?.text = usernames[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return usernames.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return 26
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]!{
return self.sections
}
func tableView(tableView: UITableView,
sectionForSectionIndexTitle title: String,
atIndex index: Int) -> Int{
return index
}
func tableView(tableView: UITableView,
titleForHeaderInSection section: Int) -> String?{
return self.sections[section] as? String
}
and it all works pretty good except for the grouping which makes my table view end up like this:
So I know you should be able to use the filtered function in an Array, but I did not understand how to implement it.
Any suggestions on how to proceed would be appreciated.
In Swift 4 Dictionary(grouping:by:) was introduced to group a sequence to a dictionary by an arbitrary predicate.
This example maps the grouped dictionary to a custom struct Section
struct Section {
let letter : String
let names : [String]
}
...
let usernames = ["John", "Nancy", "James", "Jenna", "Sue", "Eric", "Sam"]
var sections = [Section]()
override func viewDidLoad() {
super.viewDidLoad()
// group the array to ["N": ["Nancy"], "S": ["Sue", "Sam"], "J": ["John", "James", "Jenna"], "E": ["Eric"]]
let groupedDictionary = Dictionary(grouping: usernames, by: {String($0.prefix(1))})
// get the keys and sort them
let keys = groupedDictionary.keys.sorted()
// map the sorted keys to a struct
sections = keys.map{ Section(letter: $0, names: groupedDictionary[$0]!.sorted()) }
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellID = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let section = sections[indexPath.section]
let username = section.names[indexPath.row]
cell.textLabel?.text = username
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].names.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sections.map{$0.letter}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].letter
}
This is how I recently implemented sorted list in a tableView in Swift programmatically,
import UIKit
class BreedController: UITableViewController{
var breeds = ["A": ["Affenpoo", "Affenpug", "Affenshire", "Affenwich", "Afghan Collie", "Afghan Hound"], "B": ["Bagle Hound", "Boxer"]]
struct Objects {
var sectionName : String!
var sectionObjects : [String]!
}
var objectArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")
// SORTING [SINCE A DICTIONARY IS AN UNSORTED LIST]
var sortedBreeds = sorted(breeds) { $0.0 < $1.0 }
for (key, value) in sortedBreeds {
println("\(key) -> \(value)")
objectArray.append(Objects(sectionName: key, sectionObjects: value))
}
}
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
// SETTING UP YOUR 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
}
}
Download CountryList Json file and put in side your project
https://gist.github.com/keeguon/2310008
var json = NSArray()
var arr_name = NSArray()
var arrIndexSection : NSArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
override func viewDidLoad() {
let path = Bundle.main.path(forResource: "countries", ofType: "json")
let data = NSData(contentsOfFile: path! )
json = (try! JSONSerialization.jsonObject(with: data as! Data, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSArray
arr_name = json.value(forKey: "name") as! NSArray;
tableview.reloadData()
super.viewDidLoad()
}
// Side List in tableview
public func numberOfSections(in tableView: UITableView) -> Int {
return 26
}
public func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.arrIndexSection as? [String] //Side Section title
}
public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int
{
return index
}
public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return arrIndexSection.object(at: section) as? String
}
// number of rows in table view
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let predicate = NSPredicate(format: "SELF beginswith[c] %#", arrIndexSection.object(at: section) as! CVarArg)
let arrContacts = (arr_name as NSArray).filtered(using: predicate)
return arrContacts.count;
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : TableViewCell=self.tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let predicate = NSPredicate(format: "SELF beginswith[c] %#", arrIndexSection.object(at: indexPath.section) as! CVarArg)
let arrContacts = (arr_name as NSArray).filtered(using: predicate) as NSArray
cell.textLabel?.text = arrContacts.object(at: indexPath.row) as? String
return cell
}
You can put your arrays with names into dictionary with letter keys.
For example
var names = ["a": ["and", "array"], "b": ["bit", "boring"]]; // dictionary with arrays setted for letter keys
then you need to access values in your dictionary in the next way
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names[usernames[section]].count; // maybe here is needed to convert result of names[...] to NSArray before you can access count property
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cellID = "cell"
let cell: UITableViewCell = self.tv.dequeueReusableCellWithIdentifier(cellID) as UITableViewCell
cell.textLabel?.text = names[usernames[indexPath.section]][indexPath.row]; // here you access elements in arrray which is stored in names dictionary for usernames[indexPath.section] key
return cell
}
In case, if your data array is not predefined, here's a way to achieve the same thing.
Let's say our class is ViewController.
class ViewController: UIViewController {
var contactDictionary = [String: [Contact]]() //Contact is a model, it has firstName and lastName properties
var keys = [String]()
var alphabets = (97...122).map { "\(Character(UnicodeScalar.init($0)))" }.map { $0.uppercased() } //Populating alphabets
... // other properties
override func viewDidLoad() {
super.viewDidLoad()
//set delegate and register cell for your tableView
self.setContacts()
}
private func setContacts() {
//Loop through your array, take the firstName, and the first character of that string.
//Check the uppercase value of that character, if it's an alphabet or not, otherwise, we'd place "#" for the names starting with a number in the header.
var temp = [String: [Contact]]() //A temporary dictionary
for contact in self.contacts {
if let firstName = contact.firstName, !firstName.isEmpty { //In my case, the firstName is an optional string
let firstChar = "\(firstName.first!)".uppercased()
if alphabets.contains(firstChar) {
var array = temp[firstChar] ?? []
array.append(contact)
temp[firstChar] = array
} else {
var array = temp["#"] ?? []
array.append(contact)
temp["#"] = array
}
}
}
self.keys = Array(temp.keys).sorted() //Populating and sorting all the keys alphabetically.
for key in self.keys { self.contactDictionary[key] = temp[key] }
//reload table
}
}
extension: ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return self.contactDictionary.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.contactDictionary[keys[section]]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let key = self.keys[indexPath.section]
let cell: //dequeue your cell here.
if let row = self.contactDictionary[key]?[indexPath.row] {
cell.display(with: row) //Bind your cell's outlets with the properties
return cell
}
//handle error
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let key = self.keys[indexPath.section]
if let row = self.contactDictionary[key]?[indexPath.row] {
//handle selection.
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { //You can use viewForHeaderInSection either.
return self.keys[section]
}
}
var frndsName = ["Vanitha","Ilakkiya","Parveen","Divya","Seetha","Madhavi","Ashwini","Sangeetha","Swathi","Don","Priyanka","Tamilselvi","Premlatha","Prashanthi","Rekha","Ajitha","Praveena","Indhusree","Nisha","Priya","Lavanya","Sandhiya","Gejalakshmi","Pavithra","Abinaya"]
let sections = ["*","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","#"]
var dividedArray:NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
for i in sections{
let dummyArray:NSMutableArray = []
for j in frndsName{
if i.first! == j.first! {
dummyArray.add(j)
}
}
dividedArray.add(dummyArray)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 26
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dividedArray[section] as! NSMutableArray).count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let dummyArray = dividedArray[indexPath.section] as! NSMutableArray
cell?.textLabel?.text = dummyArray[indexPath.row] as? String
return cell!
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.sections
}
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return index
}
internal func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section] as String
}
}
var nameList = ["Abc","Bbc","Cbc",......]//whatever it is
var arrNameList = [[nameList]]()
var str = String()
override func viewDidLoad() {
str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i : Int in 0 ..< (str.count) {
var arr = [nameList]()
for j : Int in 0 ..< nameList.count {
let name = nameList[j]
let index = str.index(str.startIndex, offsetBy: i)
let char = str[index]
if name.first == char {
arr.append(name)
}
}
arrNameList.append(arr)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return arrNameList.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection
section: Int) -> String? {
let index = str.index(str.startIndex, offsetBy: section)
let char = str[index]
return char
}
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return arrNameList[section].count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection
section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath:
IndexPath) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as! NameListTableViewCell
let name = arrNameList[indexPath.section][indexPath.row]
cell.nameLbl.text = name
cell.selectionStyle = .none
return cell
}

Resources