Featch data to tableview - arrays

In my first vc (ViewController) I have button with action performSegue. In override func prepare(for segue:) I want to send data to another view controller.
This is my code:
if segue.identifier == "nextVC" {
let data1 = ["TITLE", "TITLE2"]
let data2 = ["DESCRIPTION", "DESCRIPTION 2", "DESCRIPTION 3"]
let destination = segue.destination as! DestinationController
destination.cellString1 = data1
destination.cellString2 = data2
destination.array = array
In my second vc (DestinationController) I have variable cellString1, cellString2 and array like below:
var array: [String] = []
var cellString1: [String] = []
var cellString2: [String] = []
In array I send to second vc id of tableView cell in first vc like below:
["0", "1", "1", "0", "1"]
In second vc I have tableView too with code (in tableview(cellForRowAt:))like below:
if array[indexPath.row] == "0" {
cell.textLabel?.text = cellString1[indexPath.row]
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 16)
cell.backgroundColor = UIColor.black
return cell
} else if array[indexPath.row] == "1" {
cell2.textLabel?.text = cellString2[indexPath.row]
cell2.textLabel?.textColor = UIColor.gray
cell2.textLabel?.font = UIFont.systemFont(ofSize: 12)
cell2.backgroundColor = UIColor.red
return cell2
where I want to detect if array in cell have value (0 or 1) then label of cell take value from cellString1 or cellString2 and show text of this label. When I delete cells textLabel configuration, colors of cells background are correct (black, red, red, black, red) however in full code I have error (Index out of range) in line cell.textLabel?.text = cellString1[indexPath.row].
Is possible to fix that?

This should be :
destination.cellString1 = data1
destination.cellString2 = data2
destination.array = array
let destination = segue.destination as! DestinationController
you should perform segue after destination.cellString1 = data1, destination.cellString2 = data2 and destination.array = array. Else these properties won't be assigned.

This is expected because the 3 arrays have different count , and sure indexPath will exceed for cellString1 as it contains 2 items , and second "0" of array is in index 3 which exceeds count of cellString1

You got 2 titles, 3 descriptions and 5 color flags. If you are using multiple arrays as data source you have to make sure that the number of items are always the same.
For example if you return array.count in numberOfRows then cellForRow is called 5 times. But there is no item at indexPath.row > 1 in cellString1 and indexPath.row > 2 in cellString2. This causes the out-of-range exception.
Basically you are strongly discouraged from using multiple arrays as data source. Don't do that.
Use a custom struct instead and rather than "0" and "1" strings use a Bool
struct Item {
var title : String
var description : String
var colorFlag : Bool
}
Then create Item instances with the appropriate data and pass one array.

Related

Pass editingDidChange Text Value From TableView Cell to Model

I have a TableView with multiple sections and would like to use editingDidChange in each cell to update the text fields. I can pass data easily enough from the UITableView cell's class to the ViewController that will update the array model, however I can't think of a way to pass along info on which cell is being edited (and therefore which index in the array should be changed).
I've used sender.tag in similar scenarios before, however the tag's only count up from each section when headers are involved. How can I tell the ViewController what cell is being edited?
Thanks!
//TableView cell class
#IBAction func textField(_ sender: UITextField) {
updateTextForDelegate.didUpdate(text: sender.text ?? "") //using editingDidChange
}
you can use like this to get cell indexpath.row for finding which cell editing.
func textFieldDidBeginEditing(_ textField: UITextField) {
var v : UIView = textField
repeat { v = v.superview! }
while !(v is UITableViewCell)
let cell = v as! FeedbackTableViewCell // or UITableViewCell or whatever
let ip = self.tableview.indexPath(for: cell)
textField.text = cell.anstxt.text
// and now we have the index path! update the model
let arrlist = arrfeedback[ip?.row ?? 0]
}
In your cellForRowAt method, you can assign your textField tag as follows:
cell.yourTextField.tag = (indexPath.section * 100) + (indexPath.row)
Then in your textFieldDidBeginEditing you can get the indexPath as follows:
func textFieldDidBeginEditing(_ textField: UITextField) {
let tag = textField.tag
let sectionBeingEdited = tag / 100
let rowBeingEdited = tag%100
let indexPath = IndexPath(row: rowBeingEdited, section: sectionBeingEdited)
let cell = self.servicesTable.cellForRow(at: indexPath)
// you have got your cell
}
NOTE: This is just a hack to get the indexPath considering the max
number of section could be 100. You can increase the value from 100 to whatever you want.

Get values from a textfield array

I would like to access the values of my textfield array but confused as the array I created is with tags.
So anyone knows how to get the value of the list (array) I created?
I want to create a function where I :
Get the value of the textfields on a list
Sort them by tags
get the value of each individual textfield
concatenate them in a string
1.Your collection Outlet will be something like this
#IBOutlet var textFields: [UITextFields]!
2. Sort it by tag
textFields.sort { $0.tag < $1.tag}
3. Use for loop to get value from array and concatenate it
var string = ""
for item in textFields {
string += item.text
}
Let's say you have following array,
var txtArray:[UITextField] = [UITextField]()
for i in 0...4 {
let txtField = UITextField(frame: .zero)
txtField.text = "\(i)"
txtField.tag = i
txtArray.append(txtField)
}
To get values you have to do following,
let sorted = txtArray.sorted { $0.tag < $1.tag }
let values = sorted.map { return $0.text! }
let test = values.joined(separator: " ")
print(test)
Output will be
0 1 2 3 4
Create an outlet connection and connect all your textfields to the same.
An outlet connection looks like
#IBOutlet strong var labels: [UILabel]!
Then to get all textfield contents and to append the same.
var resultString = ""
for item in enumerate(self.labels) {
resultString = resultString + item.text
}
Assume that you have array of UITextField
let textfield1 = UITextField()
textfield1.tag = 1
textfield1.text = "1"
let textfield2 = UITextField()
textfield2.tag = 2
textfield2.text = "2"
let textfield3 = UITextField()
textfield3.tag = 3
textfield3.text = "3"
let arrayOfTextFields :[UITextField] = [textfield2,textfield1,textfield3]
let result = self.getInputsValue(arrayOfTextFields, seperatedby: "-")
print(result)
Method you want :
func getInputsValue(_ inputs:[UITextField], seperatedby value: String) -> String {
return inputs.sorted {$0.tag < $1.tag}.map {$0.text}.compactMap({$0}).joined(separator: value)
}
Result:
1-2-3

How to append an array in another array in Swift?

I have a JSON response whose answer I have to parse. I write the single elements into an array called courseDataArray using a for loop. After that, I want to write this newly created array into another array called combinedCourseArray with the aim to pass that on to a UITableView. Creating the first array seems to work fine.
But how can I create another array combinedCourseArray who contain all arrays of type courseDataArray?
for (index, element) in result.enumerate() {
// get one entry from the result array
if let courseEntry = result[index] as? [String:AnyObject]{
//work with the content of the array
let courseName = courseEntry["name"]
let courseType = courseEntry["course_type"]
let courseDate = courseEntry["cor_date"]
let courseId = courseEntry["cor_id"]
let duration = courseEntry["duration"]
let schoolId = courseEntry["sco_id"]
let status = courseEntry["status"]
let courseDataArray = ["courseName" : courseName, "courseType": courseType, "courseDate": courseDate, "courseId": courseId, "duration": duration, "schoolId":schoolId, "status":status]
print(courseDataArray)
var combinedCourseArray: [String: AnyObject] = [:]
combinedCourseArray[0] = courseDataArray //does not work -- error: cannot subscript a value of type...
// self.shareData.courseStore.append(scooter)
}
You should move the combinedCourseArray declaration outside of the array. It should be var combinedCourseArray: [[String: AnyObject]] = [[:]] since it's an array and not a dictionary.
And you should be doing
combinedCourseArray.append(courseDataArray)
instead of
combinedCourseArray[0] = courseDataArray
var FirstArray = [String]()
var SecondArray = [String:AnyObject]()
FirstArray.append(contentsOf: SecondArray.value(forKey: "key") as! [String])
First declare this combinedCourseArray array out side this loop
var combinedCourseArray: [[String: AnyObject]] = [[String: AnyObject]]()
for (index, element) in result.enumerate() {
// get one entry from the result array
if let courseEntry = result[index] as? [String:AnyObject]{
//work with the content of the array
let courseName = courseEntry["name"]
let courseType = courseEntry["course_type"]
let courseDate = courseEntry["cor_date"]
let courseId = courseEntry["cor_id"]
let duration = courseEntry["duration"]
let schoolId = courseEntry["sco_id"]
let status = courseEntry["status"]
let courseDataArray = ["courseName" : courseName, "courseType": courseType, "courseDate": courseDate, "courseId": courseId, "duration": duration, "schoolId":schoolId, "status":status]
print(courseDataArray)
combinedCourseArray.append(courseDataArray) //does not work -- error: cannot subscript a value of type...
// self.shareData.courseStore.append(scooter)
}
}
Just use flatMap on the outer array to translate one array into another array, possibly dropping some elements:
let courseDataArray : [[String:AnyObject?]] = result.flatMap {
guard let courseEntry = $0 as? [String:AnyObject] else {
return nil
}
return [
"courseName" : courseEntry["name"],
"courseType": courseEntry["course_type"],
"courseDate": courseEntry["cor_date"],
"courseId": courseEntry["cor_id"],
"duration": courseEntry["duration"],
"schoolId": courseEntry["sco_id"],
"status": courseEntry["status"]
]
}
Of course, the guard isn't really necessary since the input type is presumably already [[String:AnyObject]] and since you then can't have any internal failures, you can just use map instead of flatMap

Setting a cells textLabel from an array of [String]()

Trying to access and set my cells textLabel and detail text label to objects i have appended to the array. Im not to sure how to use the right syntax in this case. thanks for the help!
heres the objects I've appended from parse in my for loop.
var customers = [String]()
for object in objects {
self.customers.append(object["customerName"] as! String)
self.customers.append(object["customerStreetAddress"] as! String)
cellForRowAtIndexPath {
cell.textLabel.text = //I want the objects["customerName"] here
cell.detailTextLabel.text = // objects["customerStreetAddress"] here
}
You could try this.
var customers = [String]()
var number = -1
for object in objects {
self.customers.append(object["customerName"] as! String)
self.customers.append(object["customerStreetAddress"] as! String)
cellForRowAtIndexPath {
++number
if number + 1 <= customers.count {
cell.textLabel.text = customers[number]//I want the objects["customerName"] here
}
++number
if number + 1 <= customers.count {
cell.detailTextLabel.text = customers[number]// objects["customerStreetAddress"] here
}
}
}

Change array back to dictionary - SWIFT

I have a for loop that creates a dictionary and then I append the dictionary to an array. I append the dictionary to an array because I don't know how to add more than one value with the same key, when I do that in the for loop the key / value pair is just updated and the old key / value pair is deleted What is the best way to change the array back to a dictionary?
import UIKit
class ViewController: UIViewController {
var jobTitle = ""
var jobDescription = ""
var dict:[String: AnyObject] = ["jobTitle": "jobTitle", "jobDescription": "jobDescription"]
var tArray = [[String: AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for var i = 0; i < 3; ++i {
jobTitle = "job1"
jobDescription = "Desc1"
dict["jobTitle"] = "job1"
dict["jobDescription"] = "Desc1"
tArray.append(dict)
}
println("\(tArray)")
}
}
Like such, where you have more than one value associated with each key:
let jobnames = ["j1", "j2", "j3"]
let jobdescs = ["d1", "d2", "d3"]
var dict : [String:[String]] = [:]
for index in 0..<3 {
if nil == dict["jobTitle"] { dict["jobTitle"] = [] }
if nil == dict["jobDesc" ] { dict["jobDesc" ] = [] }
dict["jobTitle"]!.append(jobnames[index])
dict["jobDesc" ]!.append(jobdescs[index])
}
Here is the output:
You call the same assignmenta such as
jobTitle = "job1"
at every iteration of the loop. Of course the variable will always contain the same value. The same is true for dict. It is an ivar, so you keep overwriting it.
What you want is to create a new collection of type [String: AnyObject] to add to your array.
let newDict:[String : AnyObject] = [titleKey : titleText,
descriptionKey : descriptionText]
tArray.append(newDict)

Resources