Show row in section with same name of row value - ios

I have a Struct of products, taken from Firebase db, like this:
struct Product {
var name: String
var type: String
var ingredients: String
var price: Double
}
and i want to populate a tableview with section (product type) and relative rows.
So I created an array with all product type:
let array = product.compactMap{$0.type}
Then i have removed duplicates and i used final array for numberofSection and titleForHeaderInSections and it works.
But now i want to show in each section only products with same type of section name.
How can I work on this?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return product.count
}

You can group your products in a dictionary by type
let dict = Dictionary(grouping: product, by: { $0.type})
and then access that using your array of types
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let type = typesArray[section]
guard let count = dict[type]?.count else {
return 0
}
return count
}
Another option would be to creating the dictionary directly with the array index as key so it can be used directly in the tableView:numberOfRowsInSection
Dictionary(grouping: product, by: { typesArray.firstIndex(of: prod.type)! })

You can add struct Category for easier data manipulation. Just make a category for all product types and filter de the products that you need. With an array of categories that contains an array of products you will have all the information you need: products, count, type etc...
struct Category {
var type: String
var products: [Product]
}
let allProducts = [Product]()
let categorySet: Set<String> = allProducts.map({ $0.type }).toSet()
let categorys: [Category] = categorySet.map { (type) -> T in
return Category(type: type, products: allProducts.filter({ $0.type == type}) )
}
func numberOfSections(in tableView: UITableView) -> Int {
return categorys.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categorys[section].products.count
}
func tableView( tableView : UITableView, titleForHeaderInSection section: Int)->String
{
return categorys[section].type
}

Use filter like this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return product.filter { $0.type == "myType" }.count
}

Related

MVVM proper ViewModel format creation to display data in tableview swift iOS

I want to create a view model with proper format which can be used to display the data inside tableview.
Expected output:
Expected output screenshot image
I've tried to create a view model as below but I was not able to create it in proper format and it's not working.
struct MyViewModel {
var headerlist : [String]
var listItem : [ListData] {
get {
return [ListData(title: "Check Detailed Info", type: .INFORMATION),ListData(title: "Check Document", type: .DOCUMENTS), ListData(title: "Check Policy", type: .DOCUMENTS)]
}
}
}
struct ListData {
var title: String
var type: HeaderType
}
enum HeaderType {
case INFORMATION
case DOCUMENTS
}
How to create a view model which can be used in tableview delegate methods like below.
let viewModel = MyViewModel()
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.headerlist.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionitem = viewModel.headerlist[indexpath.section]
return sectionItem.listItem.count
}
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
///Will be creating a headerview and title label outlet in it.
headerView.titleLabel.text = viewModel?.headerlist[section]
return headerView
}
I just found some links looking to get proper understandable answer
UITableView with MVVM using Swift
Populate data onto UITableView with MVVM
MVVM in TableView Cell
You have two sections, so you need two arrays in your model.
I would suggest you use something like this:
struct SectionData {
let type: HeaderType
let items: [String]
}
enum HeaderType {
case information = "INFORMATION"
case documents = "DOCUMENTS"
}
struct MyViewModel {
var sectionData : [SectionData] {
get {
return [
SectionData(type: .information, items: ["Check Detailed Info"]),
SectionData(type: .documents, items:["Check Document","Check Policy"])
]
}
}
}
Then you can use it in your table view
let viewModel = MyViewModel()
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.sectionData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.sectionData[section].count
}
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
///Will be creating a headerview and title label outlet in it.
headerView.titleLabel.text = viewModel.sectionData[section].type.rawValue
return headerView
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: indexPath) -> UITableViewCell? {
let cell = tableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = viewModel.sectionData[indexPath.section].items[indexPath.row]
return cell
}
Note that this isn't an MVVM approach, but perhaps you have simplified your code for the purposes of the question. If you are going to use static data it would be more efficient to create the data array in the view model init rather than use a computed property.

how can I merge two structs and print values of both in uitableviewcell in swift 3.0

Below are my two structs, and I want to print values from both structs in UITableViewCell
struct MainCell: Decodable
{
let job_id: String
let job_desig: String
let job_desc: String
let job_location: String
let job_emp_gender: String
let job_skills: String
let company_id: Int
}
struct Company: Decodable{
let company_id: Int
let company_name: String
}
var mainCellData = [MainCell]()
var companyData = [Company]()
- TableView Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return mainCellData.count + companyData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:JobDetails_TableViewCell = tableView.dequeueReusableCell(withIdentifier: "jobCell") as! JobDetails_TableViewCell
for jobs in mainCellData {
cell.lblDesig.text = jobs.job_desig
cell.lblDesc.text = jobs.job_desc
cell.lblLocation.text = jobs.job_location
cell.comName.text = jobs.name.company_name
}
return cell
}
As I want to print job_desig, job_desc and job_location from my first struct (struct MainCell: Decodable) and company_name from my second struct (struct Company: Decodable)
Can anybody help me with my issue?
Your numberOfRowsInSection doesn't match your requirement.
Get rid of the for loop in cellForRowAt.
You don't need to merge anything. You need to look up the company name based on its id.
Your code should look like this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mainCellData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:JobDetails_TableViewCell = tableView.dequeueReusableCell(withIdentifier: "jobCell") as! JobDetails_TableViewCell
let data = mainCellData[indexPath.row]
cell.lblDesig.text = data.job_desig
cell.lblDesc.text = data.job_desc
cell.lblLocation.text = data.job_location
cell.comName.text = companyData.first { $0.company_id == data.company_id }?.company_name
return cell
}
The real trick is getting the company name. The idea is that you have data.company_id which is of course the company_id for the row being displayed. You need to iterate through the companyData array and find a Company that has the same company_id. When a match is found, get the company_name from that matching company.
The code companyData.first { $0.company_id == data.company_id }?.company_name means:
Iterate through the companyData array and find the first entry where the company_id equals data.company_id. If a match is found, return its company_name.
You don't need to add count for numberOfRow,
It is not good practice to manage two array for tableview you should combine in one struct like below
You can create one struct to maintain your all datasource
struct MainStruct {
var mainCellData :MainCell
var companyData :Company?
}
EDIT
and fill your data source like this in viewDidLoad or whenever you got your array
var data = [MainStruct]()
for object in mainCellData {
let obj = companyData.first{$0.company_id == object.company_id }
data.append(MainStruct(mainCellData: object, companyData: obj))
}
Now
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:JobDetails_TableViewCell = tableView.dequeueReusableCell(withIdentifier: "jobCell") as! JobDetails_TableViewCell
let data = data[indexPath.row]
cell.lblDesig.text = data.mainCellData.job_desig
cell.lblDesc.text = data.mainCellData.job_desc
cell.lblLocation.text = data.mainCellData.job_location
cell.comName.text = data.companyData?.company_name
return cell
}
Hope it is helpful

How to populate UITableView with data from a grouped struct in a dictionary?

I have the following struct that contains data from parsed JSON.
struct callRailData {
var callDate: String
var userDetails = callData()
}
struct callData{
var callerName: String?
var callerNumber: String?
var callerCityName: String?
var callerCountryName: String?
var callerStateName: String?
var callAnsweredState: Bool?
var callDirection: String?
var callDuration: String?
var callRecordingURL: String?
var callRecordingPlayer: String?
var callSource: String?
var callCompanyName: String?
}
I need to display this data in a UITableView with 'callDate' as section header. So I grouped the struct in this dictionary:
var user = [callRailData]()
var sections = Dictionary<String, [callRailData]>()
sections = Dictionary(grouping: user, by: { $0.callDate }).
I do not know how to display this data in the tableview. How do I get numberOfSections and numberOfRowsInSection from 'sections'.
Please help I am a beginner in Swift and iOS development.
Generally, we use array as datasource for tableview. Provide numberOfRows= array count and "cellForRow" datasource object from array.
i think you dont need to do grouping like that..
jus do it like that hope it will work.
override func numberOfSections(in tableView: UITableView) -> Int {
return user.count
}
it will make sections on the basis of your user count.
now in every section get one row to show data.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "your cell", for: indexPath) as! Your Cell class
cell.callerNameLabel.text = user[indexpath.section].userdetails.callerName
return cell
}
this func will set your sec header title
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return user[section].callDate
}

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
}

Adding index at uitableview is not working in Swift 2.0

I am loading contacts in UITableView and I want to add index at the right end for user to navigate through contacts.
I am using the code:
var indexOfNames = [String]()
let indexNames = "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"
indexOfNames = indexNames.componentsSeparatedByString(" ")
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return indexOfNames
}
func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
let temp = indexOfNames as NSArray
return temp.indexOfObject(title)
}
But it is not working. When I tap on the index, the table view comes to the top row. i.e. A. I have set the delegates for tableview. Maybe there is some issues with Swift 2.0?
Adding index to UITableView working for me may help you (for swift 2.0):
var arrIndexSection : NSMutableArray = ["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"]
//MARK:- TableView Datasource/DataDelegate Method
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return arrIndexSection.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return arrIndexSection.objectAtIndex(section) as? String
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return self.arrIndexSection as? [String]
}

Resources