Unable to assign the value of selected row to a variable - ios

I have a tableView controller that is pulling data from JSON, the table contains sections and row data using the following structure:
import UIKit
struct Section {
let name : String
let items : [Portfolios]
}

You probably forgot to respecify the value of structure in your didSelectRowAtIndexPath.
Therefore please change your tableView's didSelectRowAtIndexPath method to:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Add this line
structure = sections[indexPath.section].items
let theStructure = structure[indexPath.row]
codeSelected = theStructure.code
// ... code selected must have taken the correct value
}

Related

How to apply tableview cell accessory to a tableview record

Explanation:
I have a UITableView that is being populated from JSON. The purpose of the tableview is for the user to select individual row records and have the checkmark accessory appear as a result.
The issue is that while I can get the checkmark to appear for whichever row is selected the checkmark is applied to the row, not the record itself.
For example, if I have two rows in the tableview and I select the first row, a checkmark is applied to it, but after updating the API to remove the row and reloading the tableView the first-row disappears but the checkmark is applied to what was the second record.
This is what my didSelect method looks like:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let section = sections[indexPath.section]
structure = sections[indexPath.section].items
let theStructure = structure[indexPath.row]
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
This is how the structure is defined for the JSON:
struct Section {
let name : String
let items : [Portfolios]
}
struct Portfolios: Decodable {
let code: String
let maker: String
}
Essentially I need help applying the checkmark to the actual record itself not just the static row.
The most efficient way is to add the isSelected information to the data model (Portfolios)
struct Portfolios : Decodable {
var isSelected = false
// other members
}
You might add also CodingKeys to exclude isSelected from being decoded.
In cellForRowAt set the checkmark according to isSelected
let item = sections[indexPath.section].items[indexPath.row]
cell.accessoryType = item.isSelected ? .checkmark : .none
In didSelectRowAt toggle isSelected and reload the row
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
sections[indexPath.section].items[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
}
First Take an empty array of record and then add checked record to this empty array. In Tableview cellforRow check if a record is in this empty array or not. If it is present in this empty array then display checkmark else remove the checkmark.
Tabelview cells get recycel. You need to overwrite prepareForReuse and clear the selected state there.
override func prepareForReuse() {
super.prepareForReuse()
isSelected = false
}
As for the top answer:
Following the state in your data model is fine too as you set the state for each cel (which solves your problem). BUT if you don't need the state other then for deleting entries, then storing the state is pointless. Thing is, all elements in your data model have the state of not selected. So why store an identical information? It is a redundant information that cost you memory for each element. In this case is overriding the prepareForReuse function the best approach.

Good way to display Tableview from object - iOS Swift

I have an object which has properties and I want to display each property as tableview row. How should I prepare my datasource
For eg:
struct Car {
var make: String
var model: String
var year: String
var vin: String
}
let ford = Car(make: Ford, model: Mustang, year: 2018, vin: 1234)
Now in my tableview i need to display like below i.e., each property as a table row cell
How do I prepare my data source?
I understand that I need to add this to array with propertyname: value like
["make":"Ford", "model":"Mustang", ...]
but how can i do that and how can i parse it to display in my cellForRow method.
Please advice
This is just sample. In my actual struct I have more than 20 properties and each needs to be display in table row. So wanted this to be in tableview
Assuming you know your structure...
Create a custom table view cell, with a "property name" label and a "value" label (as shown in your image).
Add class variables:
let propertyArray = [
"Make",
"Model",
"Year",
"VIN"
]
var valueArray: [String] = [String]()
when you've selected a Car object,
valueArray = [
selectedCarObject.make,
selectedCarObject.model,
selectedCarObject.year,
selectedCarObject.vin
]
Now, your tableView implementation can use:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell", for: indexPath) as! MyCustomCell
cell.propertyLabel.text = propertyArray[indexPath.row]
cell.valueLabel.text = valueArray[indexPath.row]
return cell
}
var modelDictionary = ["make":"Ford", "model":"Mustang", ...]
Your modelDictionary will be your datasource, im assuming your cell has two label which you will put the data of key and value of the dictionary.
how will you make an Dictionary of your model data?
You can try creating a function on your model to create an Dictionary for each property it has.
Hope i answer you question.

Swift looping through array

I have a UITableView that has 100 cells. I want to create an array that will hold index values of that table that I want to disable the table cells if the table row selected matches any of the values in the array.
I have found that the following code works to disable a specific cell that I give it.
UITableViewCellSelectionStyle.none
Any help on this would be greatly appreciated.
This is how I am checking which cell is selected:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedRow = tableView.indexPathForSelectedRow?.row
let workoutSelected = selectedRow
stringPassedTableView = workoutSelected!
let myVC = storyboard?.instantiateViewController(withIdentifier: "showWorkout") as! WorkoutViewController
myVC.stringPassed = stringPassedTableView
navigationController?.pushViewController(myVC, animated: true)
}
You can use the following tableview delegate method to allow selection or not
tableView:willSelectRowAtIndexPath:
Simply check if the cell index is in your disabled cell indexes and if so return nil. Otherwise return the indexpath.
You can see the documentation here:
https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614943-tableview?language=objc#return-value
A much better way that, create an array of your model class which data you are passing into tableView data source.
Add a property into model class like named as "isSelectable" and assign it properly when you are parsing your model class data.
Use this "isSelectable" property, when you will select a row then check this property it is true or false and performs operation accordingly.
Hope you understand !!
You have an array (or set) as a class property
var disabledRows = [IndexPaath]()
then simply use it at the start of the func
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if disabledRows.contains(indexPath) { return }
// code to handle row with enabled cell
}

Passing Dictionary into table view using swift 4

I have Created two Dictionary of question and answer , and I have created two label in my table view for displaying question and their options serial wise , but after displaying the result into the table view it is shown as the given screenshot , help me to show these data in standard for of question and answer with options
*I have created Dictionary of two*
`[Int:String]`and [Int:Array<String>]
, *and now I want access it in my Table view serially with dictionary1 in question label and dictionary2 in answer label;*
Code --
var dictionary1:[Int:String] =
[0:"Whether you have experienced Pricking-pain, Desquamation,itching or dry skin sensation during seasonal alternate.",
1:"Whether your skin apt to flush( Redness) in hot humid environment ",
2:"Whether your skin has multiple disernible dilated capillaries.",
3:"whether you have once been diagnosed atopic dermatitis or seborrheic dermatitis."]
Dictionary2 for creating options to the questions
var dictionary2 : [Int:Array<String>] =
[0:["Never","Seldom","Usually","Always"],
1:["Never","Seldom","Usually","Always"],
2:["Never","Seldom","Usually","Always"],
3:["Yes", "No"]]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictionary1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.questionLabel.text = dictionary1[indexPath.row]
cell.questionLabel.textColor = UIColor.black
let arr = dictionary2[indexPath.row]
var strr = String()
for str in arr! {
strr = strr + str
}
cell.optionsLabel.text = strr
cell.optionsLabel.textColor = UIColor.black
return cell
}
}
// HERE IS THE SCREENSHOT OF MY TABLE VIEW , IT IS NOT SHOWING THE DATA IN MULTILINE AND THE OPTIONS AND THE QUESTION ARE OVERLAPPING
[![enter image description here][1]][1]
List item
[1]: https://i.stack.imgur.com/Erpvq.png
Replace below delegate with yours:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
// TO Display Single Dictionary Data
cell.textLabel?.text = dictionary1[indexPath.row]
// To display Array of string stored in dictionary
cell.textLabel?.text = dictionary2[indexPath.row]?.joined(separator: "\n")
return cell
}
For 2nd Requirement
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dictionary1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
// FOR FIRST DICTIONARY
cell.lblFirst?.text = dictionary1[indexPath.row]
// FOR SECOND DICTIONARY
cell.lblSecond?.text = dictionary2[indexPath.row]?.joined(separator: "\n")
return cell
}
Note: I wanted to make it a comment, but I also wanted to share this image so I answered, but it's a hint, not the complete answer.
The function you are using takes an array of String as input. you can see the below screen for any function by pressing the option key and clicking the function body.
You need to pass the key as a string. then your dictionary must have a key type as String. Once you make the key a string.
Possible solutions are:
if you are keeping key as Int, then use: dictionary1[indexPath.row]
if you make your key as a string then use: dictionary1["\(indexPath.row)"]
(Just for this case) If you want to show them in a sequence only like 0th element 1st element.. then why not use an Array instead of Dictionary.
arry = ["1st description","2nd description"]
and then use
cell.label.text = arry[indexPath.row]

UITableView first row '0' wont update upon table reload - all others do?

I have a one view app with embedded UITableView that displays a list of "stores"(Realm object). By default I populate the table view of all the Store objects. IF the user wants to then narrow the results they can do so by using any combination of text fields in MasterVC. When they hit search - simply update TableView with 'filtered' Realm objects.
What works:
Populate UITableView with objects from the Realm.
Create new Realm entries via text field entries in MasterVC and repopulate table in ResultsVC.
Swipe to delete object on table / and Realm object.
What sort of works:
If user enters a search term then 'filter' the Realm object (Stores) and repopulate the table. This correctly reloads and returns the number of results. However the First Cell (0) of the TableView is always the exact same and never updates.. If there are 20 returned results in the search then Rows 1-18 are correctly displayed. Row 0 is static and never changes its text. Any obvious reasons why?
Results Table View Controller
class ResultsVC: UITableViewController {
// data source
var stores: Results<Store> = {
let realm = try! Realm()
return realm.objects(Store.self)
}()
var token: NotificationToken?
...
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stores.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! ResultsCustomViewCell
let stores = realm.objects(Store.self)
let currentStore = stores[indexPath.row]
cell.storeNumber.text = "#\(currentStore.storeNumber)"
cell.storeName.text = "\"\(currentStore.storeName)\""
return cell
}
}
Here is how I'm accessing the ResultsVC from MasterVC
Master View Controller
class MasterViewController: UIViewController {
...
#IBAction func searchDatabase(_ sender: Any) {
let CVC = childViewControllers.first as! UINavigationController
let resultVC = CVC.viewControllers[0] as? ResultsVC
result.stores = stores.filter("address = '1234 Blue Street'")
result.tableView.reloadData()
}
...
}
Turns out I had a duplicate variable which was overwriting the orig from above.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! ResultsCustomViewCell
let stores = realm.objects(Store.self) // <- OVERWRITING ORIGINAL //
let currentStore = stores[indexPath.row]
cell.storeNumber.text = "#\(currentStore.storeNumber)"
cell.storeName.text = "\"\(currentStore.storeName)\""
return cell
}

Resources