TableViewController numberOfRowsInSection section - ios

I have a controller with buttons and a TableViewController with 10 arrays. Each button has an index, which pass to TableViewController.
In TableViewController code looks like this:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if buttonIndex == 0 {
return array0.count
}
else if buttonIndex == 1 {
return array1.count
}
else if buttonIndex == 2 {
return array2.count
}
else if buttonIndex == 3 {
return array3.count
}
else if buttonIndex == 4 {
return array4.count
}
else if buttonIndex == 5 {
return array5.count
}
else if buttonIndex == 6 {
return array6.count
}
else if buttonIndex == 7 {
return array6.count
}
else if buttonIndex == 8 {
return array6.count
}
return array0.count
}
I want to automatically define current index to do this:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return array(currentIndex).count
}
How to do it?

One way to achieve what you want is by creating a map, with index as key and array as value.
So your code should look something like this:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return indicesArray[index].count
}

You can make nested array where to store your arrays like:
var mainArray = [array0,array1,array2 ... ]
Then in
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mainArray[section].count
}

You have to make the collection of your array in the array and you could be able to return as your requirement.
At class level:
var arrOfArrayData = []
Just like that:
let array0 = [""]
let array1 = [""]
let array2 = [""]
let array3 = [""]
let array4 = [""]
let array5 = [""]
let array6 = [""]
arrOfArrayData = [array0,array1,array1,array3,array4,array5,array6]
return arrOfArrayData[section].count //numberOfRowsInSection

Your list which contains 10 values as an array:
let listData = [["value11", "value12"], ["value21", "value22"], ["value31", "value32"] ...]
Inside UITableViewDataSource delegate method:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listData[section].count
}

Related

How to do section title in TableView if there is no sections in data from json?

just like title says, I would like to categorize my data by some property which I get from json.
Here is example of my json:
{
"rows": [
{
"id": 1,
"name": "Trip to London",
"status": "CURRENT",
"companyId": 395,
"approvedBy": null,
"start": "2021-01-12T00:00:00.000Z",
"end": "2021-01-13T00:00:00.000Z",
"approvedAt": null,
"updatedBy": null,
"createdAt": "2021-01-04T13:32:45.816Z",
"updatedAt": "2021-01-04T13:32:45.816Z",
"services": "Flight"
}
]
}
I have 3 states of my response, which is status: String in json response and possible values are: upcoming, current and previous. I would like to categorize my data by status property, if I get that trip is current, then put it under section title of current.
What I tried so far is this:
In numberOfRowsInSection:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching {
return self.filteredData.count
}
return bookedTrips.count
}
In viewForHeaderInSection:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: Cells.sectionTitle) as! TripsListHeaderCell
if section == 0 {
cell.configure(trips: "CURRENT")
} else if section == 1 {
cell.configure(trips: "UPCOMING")
} else {
cell.configure(trips: "PREVIOUS")
}
return cell
}
EDIT:
In cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
if isSearching {
cell.configure(trips: filteredData[indexPath.row])
} else {
cell.configure(trips: bookedTrips[indexPath.row])
}
return cell
}
And if I return number 3 in function numberOfSections, I have my section titles displayed, but since I returned count in numberOfRowsInSection, everything is duplicated. What should I do to categorize my data by status prop from json, since I don't have 2D array so I could work with sections?
And of course, if there is better way how to write viewForHeaderInSection, which I am pretty sure there is, please give me advice.
I can post some screenshots if needed if my question is not properly written and its hard to understand what I am trying to say.
Step 1 : You need to create struct for Trip like as below
struct TripStruct
{
var sectionName : String
var tripArray : [TripModel] = [] // Here TripModel == Your Trip Model
}
Step 2 : You need to group data into section
var tripStructList : [TripStruct] = [] //Here this Global Variable
var filterTripStructList : [TripStruct] = [] //Here this Global Variable
let groupedDictionary = Dictionary(grouping: allTripArray, by: { $0. status }) // Here allTripArray == Your trip array from json
let keys = groupedDictionary.keys.sorted()
self.tripStructList = keys.map({ TripStruct(sectionName: $0, tripArray: groupedDictionary[$0]!)})
Step 3 : Set data in tableView delegate and datasoure method like as below
func numberOfSections(in tableView: UITableView) -> Int
{
return isSearching ? self.filterTripStructList.count : self.tripStructList.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return isSearching ? self.filterTripStructList[section].tripArray.count : self.tripStructList[section].tripArray.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: Cells.sectionTitle) as! TripsListHeaderCell
let sectionRow = isSearching ? filterTripStructList[section] : tripStructList[section]
cell.configure(trips: sectionRow.sectionName)
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
let sectionRows = isSearching ? filterTripStructList[indexPath.section] : tripStructList[indexPath.section]
let row = sectionRows.tripArray[indexPath.row]
cell.configure(trips: row)
return cell
}
Step 4 : Search your data
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == ""
{
isSearching = false
filterTripStructList.removeAll()
self.tableView.reloadData()
return
}
else
{
isSearching = true
let filterAllTripArray = self.allTripArray.filter({$0.tripName.lowercased().contains(searchText.lowercased())}) // Here allTripArray == Your trip array from json
let groupedDictionary = Dictionary(grouping: filterAllTripArray, by: { $0.status })
let keys = groupedDictionary.keys.sorted()
self.filterTripStructList = keys.map({ TripStruct(sectionName: $0, tripArray: groupedDictionary[$0]!)})
self.tableView.reloadData()
}
}

How to return numberOfRowsInSection?

I really need help as I am new to Swift. I am facing an issue where I don't find a way to return numberOfRowsInSection
Scenario:
I have 3 numberOfSections in tableview which I am returning from sectionArray, which is as follows:
{
"mbsdcie6_2_1": "Incomer 132 KV Parameters",
"mbsdcie6_2_2": [
3,
6,
4,
5,
8,
30,
31,
7,
18,
29,
1
]
},
{
"mbsdcie6_2_1": "SMS2 Parameters",
"mbsdcie6_2_2": [
9,
10,
11,
12,
13,
14
]
},
{
"mbsdcie6_2_1": "SMS 1 Parameters",
"mbsdcie6_2_2": [
15,
17
]
}
]
}
Using above array, I can return numberOfSections like this:
func numberOfSections(in tableView: UITableView) -> Int {
return self.sectionArray.count
}
But, how to return numberOfRowsInSection using sectionArray ??
Note:
I want numberOfRows from "mbsdcie6_2_2" key of sectionArray
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return "numberOfRows" // What to return here?
}
if section == 1 {
return "numberOfRows"
}
if section == 2 {
return "numberOfRows"
}
return 0
}
Edit 1
This is how I added data into sectionArray:
// It comes from another webservice, so I added it to userdefaults.
let headers = swiftyJSonVar["message"][0]["mbsdcie6"]["mbsdcie6_2"].arrayObject
kUserDefault.set(headers, forKey: kHeadersArray)
// In my another ViewController, I am retrieving it like this:
var sectionArray = [Dictionary<String, Any>]()
override func viewWillAppear(_ animated: Bool) {
sectionArray = kUserDefault.array(forKey: kHeadersArray) as! [Dictionary<String, Any>]
print(sectionArray)
}
I know it could be silly and It's way too easy but somehow I am stucked as I am new to it.
Any help would be appreciated, Thanks!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !sectionArray.isEmpty {
let sectionContent = sectionArray[section]["mbsdcie6_2_2"] as? [Int]
return sectionContent.count
} else {
return 0
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if sectionArray.indices.contains(section),
let sectionContent = sectionArray[section]["mbsdcie6_2_2"] as? [Int] {
return sectionContent.count
} else {
return 0
}
}
try this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let singleSection = self.sectionArray[section]
if let rows = singleSection["mbsdcie6_2_2"] as? [Int] {
return rows.count
} else {
return 0
}
}

Issue when filtering with UISearchResults

So I have a list of friends coming from the API and I've tried to implement also the search functionality. So far, so good, the filtering is good, but my first section is actually a button that sends me to another VC and it 's getting irritating that that cell always appears when I try to search through the friend list. Actually, i want it to be hidden when I search for friends.
I added some pictures to make it more clear
As can be seen the third picture shows clearly the problem.
My code looks like.
var friendList = [Conversations]()
var filteredFriends = [Conversations]()
func numberOfSections(in tableView: UITableView) -> Int {
return friendList.count + 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
return filteredFriends.count
}
if section == 0 {
return 1
} else if section == 1 {
return friendList.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewGroupConversationCell") as! NewGroupConversationTableViewCell
return cell
} else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewConversationCell") as! NewConversationTableViewCell
var friendList: Conversations
if isFiltering() {
friendList = filteredFriends[indexPath.row]
} else {
friendList = self.friendList[indexPath.row]
}
cell.populate(friendList)
return cell
}
return UITableViewCell()
}
func searchBarIsEmpty() -> Bool {
// Returns true if the text is empty or nil
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredFriends = friendList.filter({( friend : Conversations) -> Bool in
return (friend.name?.lowercased().contains(searchText.lowercased()))!
})
mainTableView.reloadData()
}
func isFiltering() -> Bool {
return searchController.isActive && !searchBarIsEmpty()
}
extension NewConversationViewController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
Pls tell me if you need more explanation.
Your the numberOfSection is equal to number of friends, that's why you have the number of action button equals to number of friends, try
func numberOfSections(in tableView: UITableView) -> Int {
return 2 // your button, and your friend list
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if isFiltering() {
return 0 // hide button
}
return 1
} else if section == 1 {
if isFiltering() {
return filteredFriends.count
}
return friendList.count
}
return 0
}
Hide section 0 when you are using filtered list.
func numberOfSections(in tableView: UITableView) -> Int {
return 2 // Default 2 sections
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if isFiltering() {
return 0
}
return 1
} else {
return friendList.count
}
return 0
}

Swift: fatal error: Index out of range

I'm getting an "Index out of range" when populating a UITableView.
I don't know why it gives me error. I have a condition statement on my cell creation function which checks for the count of each array and then adds a custom cell on index 0.
If anyone knows about this problem, please tell me the solution. I've been working on it for days and can't seem to figure this one out.
var homeArr: [services] = []
var autoArr: [services] = []
Alamofire.request(url_specialist_request_url, method: .post, parameters: parameters).responseJSON {
response in
if response.data != nil {
let json = JSON(data: response.data!)
let json_count = json.count
// print(json)
self.homeArr.append(services(service_name:"",service_icon:"",service_category:""))
self.autoArr.append(services(service_name:"",service_icon:"",service_category:""))
self.personalArr.append(services(service_name:"",service_icon:"",service_category:""))
for i in 0 ..< json_count {
let categoryId = json[i]["category_id"].string!
if(categoryId == "1") {
self.homeArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
} else if(categoryId == "2") {
self.autoArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
} else {
self.personalArr.append(services(service_name:json[i]["service_name"].string!,service_icon:"\(json[i]["service_icon"].string!)Icon",service_category:json[i]["category_id"].string!))
}
}
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell
let home_dict = self.homeArr[indexPath.row]
// ** Index out of range on the following line **
let auto_dict = self.autoArr[indexPath.row]
if(self.homeArr.count > 1) {
if (indexPath.row == 0)
{
cell.serviceLabel!.text = "Home"
cell.contentView.backgroundColor = UIColor.blue
} else {
cell.serviceLabel!.text = home_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
}
}
if(self.autoArr.count > 1) {
if (indexPath.row == 0)
{
cell.serviceLabel!.text = "Personal"
cell.contentView.backgroundColor = UIColor.blue
} else {
cell.serviceLabel!.text = auto_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
}
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return(homeArr.count + arrAuto.count)
}
This is what I want to achieve
Home Arr cell
value1
value2
Auto Arr cell
value1
value2
Create two sections One for HomeArr and one for AutoArr. I believe for each section you wanna show a additional cell with some title. So below code should help you.
extension ViewController : UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return (homeArr.count > 0) ? homeArr.count + 1 : 0
}
else {
return (autoArr.count > 0) ? autoArr.count + 1 : 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell
if indexPath.section == 0 {
if (indexPath.row == 0)
{
cell.serviceLabel!.text = "Home"
cell.contentView.backgroundColor = UIColor.blue
} else {
let home_dict = self.homeArr[indexPath.row - 1]
cell.serviceLabel!.text = home_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
}
}
else {
if (indexPath.row == 0)
{
cell.serviceLabel!.text = "Personal"
cell.contentView.backgroundColor = UIColor.blue
} else {
let auto_dict = self.autoArr[indexPath.row - 1]
cell.serviceLabel!.text = auto_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
}
}
return cell
}
}
EDIT:
As pointed out by rmaddy in comments below
Why the extra row in each section? Why not use a section header
instead?
As we are not aware of OP's exact requirement I am updating my code to show section title as well.
extension ViewController : UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return homeArr.count
}
else {
return autoArr.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "serviceCell",for:indexPath) as! servicesCell
if indexPath.section == 0 {
let home_dict = self.homeArr[indexPath.row]
cell.serviceLabel!.text = home_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(home_dict.service_icon)")
}
else {
let auto_dict = self.autoArr[indexPath.row]
cell.serviceLabel!.text = auto_dict.service_name
cell.serviceIcon!.image = UIImage(named:"\(auto_dict.service_icon)")
}
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Home Arr cell"
}
else {
return "Auto Arr cell"
}
}
}

Group and sort Backendless data in UITableview with Swift

I'm looking to group and sort a list of users from backendless, similar to iPhone contacts. I want to add sectionIndexTitlesForTableView(_:), titleForHeaderInSection(_:), and sectionForSectionIndexTitle(_:). I haven't found a tutorial on how to do this, and I have been stuck for weeks.
So far, I'm able to retrieve users and populate the table view. I also implemented UISearchBarDelegate.
var users: [BackendlessUser] = []
var filteredUsers : [BackendlessUser] = []
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableView {
return users.count
} else {
return self.filteredUsers.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.tableView {
let user = users[indexPath.row]
cell.textLabel?.text = user.name
} else {
let filteredUser = filteredUsers[indexPath.row]
cell.textLabel?.text = filteredUser.name
}
return cell
}
You must have a dictionary of array (name 'data' for example)
data["A"] = ["Ananas", "Anaconda", "Apple"]
data["B"] = ["Banana", "Baby"]
...
data["Z"] = ["Zoro"]
begin:
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var headers: [String] = []
var data : [String: [String]] = [:] // Choose your type
override func viewDidLoad(){
// Do your stuff...
headers = letters.keys.sort()
// init your data var
data = ...
tableView.reloadData()
}
for header:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return headers.count
}
func sectionHeaderTitlesForTableView(tableView: UITableView) -> [String]?{
return headers
}
func tableView: UITableView, titleForHeaderInSection section: Int) -> String?{
return headers[section];
}
cell
func tableView(tableView: UITableView, numberOfRowInSection section: Int) -> Int {
// Exemple
return data[section].count
}

Resources