swift dictionary in tableview - ios

I has add struct
struct lists {
var title : String!
var description : String!
}
create dictionary:
var list = Dictionary<String, String>()
var listArray = [lists]()
update data to dictionary:
list.updateValue("InquiryNumberCode", forKey: InquiryNumberCode)
list.updateValue("InquiryNumberDescription", forKey: InquiryNumberDescription)
list.updateValue("InquiryNumberValue", forKey: InquiryNumberValue)
run for loop to append listArray:
for (description, title) in list {
print("\(title): \(description)")
listArray.append(lists(title: title , description: description ))
}
Tried insert data to Tableview cell has same error.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detail", for: indexPath) as! DetailTableViewCell
let celldata = listArray[indexPath.section]
cell.titleOutlet.text = celldata.title[indexPath.row]
return cell
}
error:
Cannot assign value of type 'Character' to type 'String?'
I can't transfer data to Tableview cell, have any one can told me why?

listArray is an Array of lists structs. So to access title, you should change your code to:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detail", for: indexPath) as! DetailTableViewCell
let celldata = listArray[indexPath.row]
cell.titleOutlet.text = celldata.title
return cell
}

Related

Swift Tableview checkmark disappeared after relaunch viewcontroller

In my case, I am loading JSON data into tableview. Here, the tableview cell multiple cell selection checkmark and uncheckmark options implemented. If go previous viewcontroller and comeback again tableview controller then last selected checkmark disappeared. How to store it?
JSON Codable
// MARK: - Welcome
struct Root: Codable {
let status: Bool
let data: [Datum]
}
// MARK: - Datum
struct Datum: Codable, Hashable {
let userid, firstname, designation: String?
let profileimage: String?
}
Custom Cell Class
class MyCustomCell: UITableViewCell {
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var nameCellLabel: UILabel!
#IBOutlet weak var subtitleCellLabel: UILabel!
}
Code for Tableview Checkmark
var studentsData = [Datum]()
var sessionData = Set<Datum>()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
let item = self.studentsData[indexPath.row]
cell.nameCellLabel.text = item.firstname
cell.subtitleCellLabel.text = item.designation
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let item = self.studentsData[indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
// UnCheckmark cell JSON data Remove from array
self.sessionData.remove(item)
print(sessionData)
} else {
cell.accessoryType = .checkmark
// Checkmark selected data Insert into array
self.sessionData.insert(item)
print(sessionData)
}
}
}
Create a means to store the checkmark status within your data struct
struct Datum: Codable, Hashable {
let userid, firstname, designation: String?
let profileimage: String?
var selected: Bool = false
}
Set the value when you create a cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
let item = self.studentsData[indexPath.row]
cell.nameCellLabel.text = item.firstname
cell.subtitleCellLabel.text = item.designation
cell.accessoryType = item.selected ? .checkmark : .none
return cell
}
And then in the didSelectRowAt replace the if block with the below to save the change back to the student data and then reset the checkmark accordingly:
self.studentsData[indexPath.row].selected.toggle()
cell.accessoryType = studentsData[indexPath.row].selected ? .checkmark : .none
You should always save the checkMark status in another array or variable.
In case only one item can be selected:
var SELECTED_ITEMS= [YOUR_DATA_TYPE]()//It must be global within tableViewController
in case multiple selection allowed
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let item = self.studentsData[indexPath.row]
if SELECTED_ITEMS.contain(item){
SELECTED_ITEMS.remove(item)
}else{
SELECTED_ITEMS.append(item)
}
}
Remember SELECTED_ITEM should be Array of your tableviewdata and SELECTED_ITEM is just the same type of your tableview data.
Also if you are initializing your model in ViewDidLoad or ViewWillAppear in tableview controller, make should SELECTED_ITEMS and SELECTED_ITEM are not reset when tableview appears.
then
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
........
cell.accessoryView = SELECTED_ITEMS.contain(item) ? .checkmark:.none// Multi Selection
.........
}
In general, you update your model, a variable or array or whatever fits in your code to keep a track of which indexpath is select/unselected. Then in cellForRowAt you can check the above variable/array... to set accessory.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath){}
will also work

How to display the data in the tableview cell from the array of array in swift

I have the values as:-
[[yes,no],[yes,no]]
i need to display in cellForRowAt indexPath in tableview .
my code:-
var tableArray:Array<[String]> = []
fetching the data from JSON:-
if let data = wholedata["data"] as? Array<[String:Any]>{
print(data)
print(response)
for question in data {
let options = question["options"] as! [String]
self.tableArray.append(options)
// self.fetchedHome.append(options as! [home])
self.no = options.count
}
print(self.tableArray)
my cell for row at index in tableview :-
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: QuestionListCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QuestionListCell
if cell == nil {
tableView.register(UINib(nibName: "QuestionListCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? QuestionListCell
}
print(reviewViewModel.tableArray)
cell.question.text = "hai"
} else {
return UITableViewCell()
}
}
How to display the data in the tableview cell?
First of all don't register the cell in cellForRow, register it in viewDidLoad.
private let identifier = "Cell" // Declare the identifier as private constant on the top level of the class.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UINib(nibName: "QuestionListCell", bundle: nil), forCellReuseIdentifier: identifier)
// do other stuff
}
Then in cellForRow get the item for index path from the data source array. As the options are an array you have to display it in two labels or join the items.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: identifier) as! QuestionListCell
let options = tableArray[indexPath.row]
cell.question.text = options.joined(separator: ", ")
return cell
}
I guess you want to display more data than the options. But at the moment you are populating the data source array only with the options
Once again as suggested in my answer to one of your previous questions I highly recommend to decode the JSON into custom structs. It makes life so much easier.
You can convert array of array into array before displaying in table and your tableViewController will only have the array of data.
You can use flatmap/compactMap to convert array of array to array:
let a = ["yes","no"]
let b = [a, a] // [["yes","no"], ["yes","no"]]
b.flatMap({$0}) // ["yes","no", "yes","no"]
This is very easy question bro.
If you don't mind using section then try this~!!!
var tableArray:Array<[String]> = []
func viewDidLoad() {
let table = UITableView()
table.register(YourNib, forCellReuseIdentifier: YourIdentifier)
}
func numberOfSections(in tableView: UITableView) -> Int {
return tableArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let tempArray = tableArra[indexPath.section] as? [String],
let cell = tableView.dequeueReusableCell(withIdentifier: YourIdentifier) as? QuestionListCell {
// just Initialize your cell with data in datasource
cell.question.text = tempArray[indexPath.row]
return cell
} else {
return UITableViewCell()
}
}

How to get data from the multiple selected rows and show in another VC tableview cell Swift4

Hello I am trying to complete my task since 2 days but still no success searched everywhere , I want to select multiple rows from tableview cells (which contains 2 labels and one image) then I want to transfer into another vc and show in tableview , I am able to select multiple rows and get this type index from selected rows but now I don't know how to get data and transfer into another vc and show in table view please help I am getting selected rows index like this [[0, 1], [0, 2], [0, 3]
VC Code
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var labone = ["1","2","3","4","5","6"]
var labtwo = ["a","b","c","d","e","f"]
var img = ["bag","bag","bag","bag","bag","bag"]
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.
}
#IBAction func button(_ sender: Any) {
let selectedindexPath = tableview.indexPathsForSelectedRows
if(selectedindexPath != nil){
let toy = labone[0]
print(toy)
print(selectedindexPath) }
else{
print("null")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labone.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let name = cell.viewWithTag(1) as! UILabel
let name_two = cell.viewWithTag(2) as! UILabel
let imgg = cell.viewWithTag(3) as! UIImageView
name.text = labone[indexPath.row]
name_two.text = labtwo[indexPath.row]
imgg.image = UIImage(named: img[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
cell.contentView.backgroundColor = UIColor.yellow
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// let selectedCell = tableview.cellForRow(at: indexPath)
if let label = cell?.contentView.viewWithTag(4) as? UIImageView {
label.image = UIImage(named: "check_disable")
}
}
}
You should use some structure like below and then update the state of item selected or deselected then when you want to go to next viewController you can filter your dataSource with the items selected like below,
class CellModel {
var labelOne: String
var labelTwo: String
var imageName: String
var isSelected = false
init(_ labelOne: String, labelTwo: String, imageName: String) {
self.labelOne = labelOne
self.labelTwo = labelTwo
self.imageName = imageName
}
}
Update your viewController,
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
let dataSource = [CellModel("1", labelTwo: "a", imageName: "bag"),
CellModel("2", labelTwo: "b", imageName: "bag"),
CellModel("3", labelTwo: "c", imageName: "bag"),
CellModel("4", labelTwo: "d", imageName: "bag"),
CellModel("5", labelTwo: "e", imageName: "bag"),
CellModel("6", labelTwo: "f", imageName: "bag")]
}
then you can update your cellForRowAt like below,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let name = cell.viewWithTag(1) as! UILabel
let name_two = cell.viewWithTag(2) as! UILabel
let imgg = cell.viewWithTag(3) as! UIImageView
let model = self.dataSource[indexPath.row]
name.text = model.labelOne
name_two.text = model.labelTwo
imgg.image = UIImage(named: model.imageName)
return cell
}
update the numberOfRowInSection with this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataSource.count
}
and you can update the state of model when cell is selected/deseleced like this,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
cell.contentView.backgroundColor = UIColor.yellow
self.dataSource[indexPath.row].isSelected = true
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// let selectedCell = tableview.cellForRow(at: indexPath)
if let label = cell?.contentView.viewWithTag(4) as? UIImageView {
label.image = UIImage(named: "check_disable")
self.dataSource[indexPath.row].isSelected = false
}
}
and finally in button action you can filter the selected models and pass to next viewController
#IBAction func button(_ sender: Any) {
let selectedItems = self.dataSource.filter({ $0.isSelected == true })
// Pass to next ViewController the selectedItmes
}
As #Rakshith suggest in their comment, move your data (labone, labtwo, img arrays) out of the view controller and into a model object. Pass that model object to your second view controller.
Also create an array selectedIndexPaths in your second view controller. When you tap the button in your ViewController, get the array of selected index paths and pass it to your second view controller.
In your second view controller's viewWillAppear, use the selectedIndexPaths variable to copy the items selected items into an array itemsToDisplay and use that in your table view data source methods to populate the second view controller's table view.

I have an array of dictionary and i would like to get an item from it and use it

var savedFaouritePlaces: NSMutableArray = [] //matched strings
Here is the info I get and I want to use this items cell for row at index path
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeartTabCell") as? HeartTabTableViewCell else {
return UITableViewCell()
}
cell.heartTabTitleLabel.text = "Wanna use that title here"
cell.heartTabImageView.image = "wanna use that image here"
return cell
}
You should use indexPath to retrieve each dictionary in that array:
let dict = savedFaouritePlaces[indexPath.row]
cell.heartTabTitleLabel.text = dict["Title"]
cell.heartTabImageView.image = UIImage(named: dict["Image"])
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "HeartTabCell") as? HeartTabTableViewCell
let dictionary = savedFaouritePlaces[indexPath.row]
cell.heartTabTitleLabel.text = dictionary["Title"]
cell.heartTabImageView.image = UIImage(named: dictionary["Image"])
return cell
}

Migration swift to swift 3 NSMutableArray

When i made the migration swift code i have this error "Type 'Any' has no subscript members" and my code is
var myArray: NSMutableArray = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = UITableViewCell()
if let name = self.myArray[(indexPath as NSIndexPath).row]["FirstName"] as? String{
cell.textLabel?.text = ("\(name)")
}
}
I tried many things but i do not have a answer for this problem.
First of all: Do not use NSMutableArray in Swift!
The error occurs because the compiler needs to know if the object is subscriptable by key. Using a native Swift type solves the problem.
var myArray = [[String:Any]]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = UITableViewCell() // will not work
if let name = self.myArray[indexPath.row]["FirstName"] as? String { // optional binding actually not needed
cell.textLabel?.text = name // please no string interpolation
}
return cell // mandatory!
}
Note: Consider that UITableViewCell() will not work. The recommended way are reusable cells
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
You should use
Generics
dequeueReusableCell
IndexPath instead of NSIndexPath
so here's the code
import UIKit
class Controller: UITableViewController {
var persons = [[String:String]]()
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellID") ?? UITableViewCell(style: .default, reuseIdentifier: "MyCellID")
cell.textLabel?.text = persons[indexPath.row]["FirstName"]
return cell
}
}

Resources