Swift UITableview display data from array - ios

I have a API that hands back a string of numbers based on a User.
Once the API Request is made the function places the numbers into an Array.
var usernumbers = userResponse["Numbers"] as NSArray
The debugger PrintLn shows:
( 16467621007,
14152555613,
14046206007
)
When I hand this to UITableView, how do I split up the array so that each number goes into a separate cell?
Ive tried:
let rowData: NSArray = tableData (usernumbers has been handed to table data)
I've tried:
cell.textLabel?.text = rowData.row (and all varieties of)
Where am I going wrong?

If i understood your problem correctly, this is what you are looking for,
cell.textLabel?.text = rowData[indexPath.row] as String
Edit:
let numberValue : NSNumber = rowData[indexPath.row] as NSNumber
let text : String = numberValue.stringValue // add nil check
cell.textLabel?.text = text
You can directly assign like
cell.textLabel?.text = numberValue.stringValue - if you are sure there won't be a nil value

Use rowData[indexPath.row] where indexPath.row is the current cell starting from 0

private let data = Array(1...9)
then...
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
and in your :
func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {...
all the usual stuff.
cell.textLabel?.text = String(format: "the magic number is : %.f", data[indexPath.row])
}

Related

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]

Access to array's indexPath in a function Swift

I am trying to access an array's indexPath inside a function to update this array's data but I don't know how to pass the indexPath as a parameter (espacially what to pass when calling) to the function or if this is even the solution.
I included cellForRowAt to illustrate how this function access indexPath.
var cryptosArray: [Cryptos] = []
extension WalletTableViewController: UITableViewDelegate, UITableViewDataSource, CryptoCellDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let crypto = cryptosArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! WalletTableViewCell
cell.setCrypto(crypto: crypto)
cell.delegate = self
cell.amountTextField.delegate = self
return cell
}
func cellAmountEntered(_ walletTableViewCell: WalletTableViewCell) {
if walletTableViewCell.amountTextField.text == "" {
return
}
let str = walletTableViewCell.amountTextField.text
let crypto = cryptosArray[indexPath.row] //<---- How to do that?
crypto.amount = walletTableViewCell.amountTextField.text
//Then update array's amount value at correct index
walletTableViewCell.amountTextField.text = ""
}
}
Instead of hacking something, simply ask the tableView to tell you the indexPath of the given cell:
// use indexPath(for:) on tableView
let indexPath = tableView.indexPath(for: walletTableViewCell)
// then you can simply use it
let crypto = cryptosArray[indexPath.row]
UITableView.indexPath(for:) documentation says:
Returns an index path representing the row and section of a given table-view cell.
And this is exactly what you want, you don't want to hack the indexPath to the cell. indexPath should be taken care of by the tableView, not the cell. Ideally, cell should be completely oblivious of its indexPath.
Always try to use the standard way to solve your problems. In general, when you are trying to solve something, I would recommend you to first look at the documentation of the UITableView, there are many useful methods there.
if you want to get index path.row when user clicked on cell , you should get index path.row when user clicked and then use this to your func
for ex :
var indexrow : int = 0
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// table cell clicked
indexrow = indexPath.row
}
func cellAmountEntered(_ walletTableViewCell: WalletTableViewCell) {
if walletTableViewCell.amountTextField.text == "" {
return
}
let str = walletTableViewCell.amountTextField.text
let crypto = cryptosArray[indexrow]
crypto.amount = walletTableViewCell.amountTextField.text
//Then update array's amount value at correct index
walletTableViewCell.amountTextField.text = ""
}

Adding a section at specific cell

I have implemented a tableView using PLIST to set properties.
I would like to add three sections at specific row. (row 12, row24, row 35)
I have tried with following code but it will be too much code and not working well.
Images and code are added below.
import UIKit
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tblStoryList: UITableView!
var array = PLIST.shared.mainArray
var array = PLIST.shared.mainArray
let sections: [String] = ["First stage","Second Stage","Third Stage"]
let s1Data : [String] = ["Row1","Row2","Row3"]
let s2Data : [String] = ["Row4","Row5","Row6"]
let s3Data : [String] = ["Row7","Row8","Row9"]
var sectionData: [Int: [String]] = [:]
override func viewDidLoad() {
super.viewDidLoad()
sectionData = [0: s1Data, 1: s2Data, 2: s3Data]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (sectionData[section]?.count)!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "StoryTableviewCell", for: indexPath) as! StoryTableviewCell
//making plist file
let dict = self.array[indexPath.row]
let title = dict["title"] as! String
let imageName = dict["image"] as! String
let temp = dict["phrases"] as! [String:Any]
let arr = temp["array"] as! [[String:Any]]
let detail = "progress \(arr.count)/\(arr.count)"
//property to plist file
cell.imgIcon.image = UIImage.init(named: imageName)
cell.lblTitle.text = title
cell.lblSubtitle.text = detail
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}
The indexPath.row you are getting in the tableView's cellForRowAt is relative to the section. You cannot use it directly as the index of your main array (which has all the rows).
You will need to perform a simple calculation to convert the indexPath.row to an index of that array (by offsetting the row with the total item count of previous sections) :
let index = [0,12,36][indexPath.section] + indexPath.row
let dict = array[index]
The same thing applies to the response you give to numberOfRowsInSection:
return [12,24,35][section]
I find it a bit odd that the data structure (PLIST) would be so rigid that it always contains exactly those number of entries and will never change. I would suggest a more generalized approach if only to avoid spreading hard coded numbers (e.g. 12,24,35,36) all over the place.
for example:
// declare section attributes in your class
let sectionTitles = ["First stage","Second Stage","Third Stage"]
let sectionSizes = [12,24,35] // central definition, easier to maintain (or adjust to the data)
let sectionOffsets = sectionSizes.reduce([0]){$0 + [$0.last!+$1] }
// and use them to respond to the table view delegate ...
let index = sectionOffsets[indexPath.section] + indexPath.row
let dict = array[index]
// ...
return sectionSizes[section] // numberOfRowsInSection
Using this approach, you shouldn't need to create sectionData (unless you're using it for other purposes elsewhere).
BTW, in your sample code, the sectionData content is hard coded with data that is not consistent with the expected section sizes so it would not work even with a correct index calculation.
you can try to use switch case in tableView:cellForRowAtIndexPath:

Error: Index out of Range UITableView

I am creating an app where it uses custom cells. I also have these UITextView's where if you input a word, that word should then go to one of the four labels I created in the custom cell. I am still coding it however I got an error saying "Error: Index Out of Range".
Here is the code, and I also commented where it is giving that error
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableView
cell.lbl.text = todolist[indexPath.row]
cell.lbl2.text = todolist2[indexPath.row] // This is the error code
cell.lbl3.text = todolist3[indexPath.row]
cell.lbl4.text = todolist4[indexPath.row]
return cell
}
Here is where I append my texts
#IBAction func ClickedforSelection(sender: AnyObject) {
todolist.append(txt.text!)
todolist2.append(txt1.text!)
todolist3.append(txt2.text!)
todolist4.append(txt3.text!)
self.view.endEditing(true)
txt.text = ""
txt1.text = ""
txt2.text = ""
txt3.text = ""
NSUserDefaults.standardUserDefaults().setObject(todolist, forKey: "list")
NSUserDefaults.standardUserDefaults().setObject(todolist2, forKey: "list2")
NSUserDefaults.standardUserDefaults().setObject(todolist3, forKey: "list3")
NSUserDefaults.standardUserDefaults().setObject(todolist4, forKey: "list4")
Here is my NumberofRowsInSection
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return todolist.count
}
I have a conjecture that it may be the reuse of indexPath.row. Any solution?
If numberOfRowsInSection is returning todolist.count, you are accessing todolist2 in your cell. If todolist has 2 items and todolist2 has 1 item, it will do this because you are trying to access an item in a list that doesn't exist. Put a breakpoint at the first call of cell.lbl.text and check each array (todolist, todolist1, etc...). You should see that todolist2 does not have have a record at whatever "row" it's calling. If that is the case, you should just test it prior to calling it. (verify todolist2.count has enough items in it - or better yet, change the code to not have 4 arrays tracking 1 row (convert to a struct of some type with all 4 values, or something similar).
First, change the following code by commenting out lines:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableView
cell.lbl.text = todolist[indexPath.row]
// cell.lbl2.text = todolist2[indexPath.row] // This is the error code
// cell.lbl3.text = todolist3[indexPath.row]
// cell.lbl4.text = todolist4[indexPath.row]
return cell
}
And test to verify existing code (should work but of course it will not update the labels.)
Then add code to print the number of items in each array:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableView
cell.lbl.text = todolist[indexPath.row]
// cell.lbl2.text = todolist2[indexPath.row] // This is the error code
// cell.lbl3.text = todolist3[indexPath.row]
// cell.lbl4.text = todolist4[indexPath.row]
print("Row: \(indexPath.row)")
print("List 1: \(todolist.count)") //this will print to the console
print("List 2: \(todolist2.count)")
print("List 3: \(todolist3.count)")
print("List 4: \(todolist4.count)")
return cell
}
What you will likely see is that they don't have the same number of items, and as soon as it his a "row" that is equal to or greater than the number of items, it will break. Remember that Row's start at Zero, while count starts at 1.
If this is what you find, then there is problem something wrong with the code where you are adding the values to the todolist arrays. If you want to see how to convert that to a struct, I can post that for you.
Converting to struct
The code that is executing when something is clicked:
#IBAction func ClickedforSelection(sender: AnyObject) {
shows that a value is written to each of the 4 todolists every time. While I don't have the full requirements, if this is what you want to do, then you could implement a struct. Put this code in it's own ToDoList.swift file (ideally):
struct ToDoListItem {
var listItem: String?
var list1Item: String?
var list2Item: String?
var list3Item: String?
}
Then replace where you define your todolislt arrays (all 4 of them) with a single:
var listItems = [ToDoListItem]() //creates an array of ToDoListItems and initializes it with no values
Then in the ClickedForSelection function, change it to:
let listItem = ToDoListItem(listItem: txt.text, list1Item: txt1.text, list2Item: txt2.text, list3Item: txt3.text)
listItems.append(listItem) //add it to your array
//todolist.append(txt.text!)
//todolist2.append(txt1.text!)
//todolist3.append(txt2.text!)
//todolist4.append(txt3.text!)
self.view.endEditing(true)
txt.text = ""
txt1.text = ""
txt2.text = ""
txt3.text = ""
// This routine will need to be updated. Leaving that for you to figure out :)
// NSUserDefaults.standardUserDefaults().setObject(todolist, forKey: "list")
// NSUserDefaults.standardUserDefaults().setObject(todolist2, forKey: "list2")
// NSUserDefaults.standardUserDefaults().setObject(todolist3, forKey: "list3")
// NSUserDefaults.standardUserDefaults().setObject(todolist4, forKey: "list4")
...then numberOfRowsInSection changes to:
return listItems.count
...then cellForRowAtIndexPath changes to:
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableView
let listItem = listItems[indexPath.row]
cell.lbl.text = listItem.listItem ?? "" // Since listItems.listItem is an optional value, ?? unwraps it safely. If it is nill, it uses "" instead
cell.lbl2.text = listItem.list1Item ?? ""
cell.lbl3.text = listItem.list2Item ?? ""
cell.lbl4.text = listItem.list3Item ?? ""
return cell
Again...I would strongly consider how you are storing a value for a todolist for all 4 lists every time (if it is a todo list app, it seems like this may not be ideal?)

Setting one parse object of type array to a tableView

I know that I can query for, lets say, users that have emailVerified equal to true and present them into a tableView, but I was having trouble getting a single Parse object of type array into a tableView. I couldn't find anything online about this specific problem, but after putting a few answers together, I got it to work my answer is below for those also having trouble with this.
Here is what I found based on my question. I have an object in Parse called "my_classes" that is of type array. I want to get the items from the array into a tableView.
1) Create a variable: var myClassesResults : NSMutableArray = []
2) Create the function or place the code where necessary:
func getUserData() {
if PFUser.currentUser()!.objectForKey("my_classes") != nil {
let classes = PFUser.currentUser()!.objectForKey("my_classes")!
myClassesResults = classes as! NSMutableArray
self.noClasses = false
self.tableView.reloadData()
} else {
self.noClasses = true
self.tableView.reloadData()
}
}
3) tableView functions:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.myClassesResults.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = myClassesResults[indexPath.row] as? String
return cell
}

Resources