How can I get the Int for the value selected in the array using a table view? - arrays

I have a table view, and when I select an item I enter a screen to where I can edit the object, and then it will bring the item back into the ViewController where the array lives. I can't seem to get the index of the selected item in the array. I would imagine I the index lives in this function as I call the segue and then send over the object for editing.
Function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "goToEditArea", sender: self)
}
Here is where I get the array to send over.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! addArea
if let selectedIndexPath = areaTableView.indexPathForSelectedRow {
// Send over the area to update
vc.area = areaArray[selectedIndexPath.row]
}
}
Basically I just need the integer value for the object so I can save in the correct slot.

In your tableView(_:didSelectRowAt:) pass indexPath.row to the performSegue(withIdentifier:sender:):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "goToEditArea", sender: indexPath.row)
}
Then, you can get that value later in prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! addArea
if let row = sender as? Int {
vc.area = areaArray[row]
}
}

Related

How to save an Array in UserDefault

I'm using a UITabBarController to create a contact list, but when I'm trying to save the array to load the data when I restart the app is giving me problems where the data isn't displayed. I'm using UserDefaults to save the data and the restore when the app is restarted.
In this code I sent data from a textfield to the array named list.
import UIKit
class NewContactoViewController: UIViewController {
#IBOutlet weak var input: UITextField!
#IBAction func add(_ sender: Any) {
if (input.text != "") {
list.append(input.text!)
UserDefaults.standard.set(list, forKey: "SavedValue")
input.text = ""
}
}
}
In this code I'm printing the data in a table, and trying to save it with user defaults.
import UIKit
var list = [String]()
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let x = UserDefaults.standard.object(forKey: "SavedValue") as? String {
return (x.count)
}
return (0)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
if let x = UserDefaults.standard.dictionary(forKey: "SavedValue") as? String {
cell.textLabel?.text = [x[indexPath.row]]
}
return(cell)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
list.remove(at: indexPath.row)
myTableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
}
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
You are saving an array of strings but you are reading a single string (or even a dictionary) which obviously cannot work. There is a dedicated method stringArray(forKey to read a string array.
Apart from the issue never read from UserDefaults to populate the data source in the table view data source and delegate methods, do it in viewDidLoad or viewWillAppear for example
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let savedArray = UserDefaults.standard.stringArray(forKey: "SavedValue") {
list = savedArray
}
myTableView.reloadData()
}
Put the data source array in the view controller. A global variable as data source is very bad programming habit.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var list = [String]()
...
In numberOfRowsInSection return the number of items in list and return is not a function, there are no parentheses
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
Same in cellForRow. Get the item from list and use reusable cells and again, return is not a function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = list[indexPath.row]
return cell
}
Note :
Consider that UserDefaults is the wrong place to share data between view controllers. Use segues, callbacks or protocol / delegate.

Passing selected String in uiTableView from Array to uiLabel in new ViewController

I have my array, my tableview setup and the table shows the array of strings. 80+ strings in an array.
Now, I select a row, and obviously I want to pass the string in that row to a uiLabel in a secondary ViewController.
placeTypes is my declared array that is not in this posted code, just imagine an array with 84 strings! My segueIdentifier is A <- easy peasy. And passedString is the uiLabel that will receive the ..well...passed string data.
TableView code
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return placeTypes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = placeTypes[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
performSegue(withIdentifier: "A", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
// let viewController = segue.destination as? ViewController
// SOMEHOW PASS THE SELECTED STRING IN THE SELECTED ROW TO THE VIEW CONTROLLER
}
}
Okay and now my ViewController code
#IBOutlet weak var passedString: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
EDIT: I am still getting errors. With the updated prepare for segue I get use of unresolved Identifier for placeTypes[indexPath.row] and viewController is telling me there is no sendString variable.
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row number: \(indexPath.row)")
performSegue(withIdentifier: "A", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
if let viewController = segue.destination as ViewController,
let indexPath = sender as IndexPath {
viewController.sendString = placeTypes[indexPath.row]
}
}
}
}
class ViewController : UIViewController {
#IBOutlet weak var passedString: UILabel!
// Put the string you need to send in a separate var
// You can't rely on the view controller being properly initalized
var sendString: String?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let sendString = sendString {
passedString.text = sendString
}
}
}
You can also take a look at legendary-potato: https://github.com/ryantxr/legendary-potato
In did didSelectRowAt pass indexPath as sender and in prepare you can cast it to IndexPath. Try this.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
performSegue(withIdentifier: "A", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
let indexPath = sender as? IndexPath {
let yourText = placeTypes[indexPath.row]
// let viewController = segue.destination as? ViewController
// SOMEHOW PASS THE SELECTED STRING IN THE SELECTED ROW TO THE VIEW CONTROLLER
}
}
}

Load dictionary with objectID and data from Parse in Swift

I'm pulling data from Parse into an array but need a way to reference that specific object directly for making changes to the data on the server (ex: deleting a specific entry off the app and having it delete on the server). Previously I was using an array filled with a PFQuery, which worked for pulling data down but not for making changes back up. I think creating a dictionary with [objectID : string of data needed] would work, so each data set currently in the array would always be paired directly to it's identifier. My issue is pulling both sets of data down (objectID and string of data) and matching them up in the dictionary. Any advice or help?
I changed the original array to a dictionary in the cellContent variable but otherwise the code is still set up for an array.
Thanks!
import UIKit
import Parse
var segueWorker = ""
class MyWorkersViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var cellContent = [String: String]()
#IBAction func backButton(_ sender: Any) {
navigationController?.popViewController(animated: true)
performSegue(withIdentifier: "workersToMyFarm", sender: self)
}
#IBOutlet weak var tableView: UITableView!
internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellContent.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")
cell.textLabel?.text = cellContent[indexPath.row]
return cell
}
override func viewDidAppear(_ animated: Bool) {
// Do any additional setup after loading the view.
self.cellContent.removeAll()
let query = PFQuery(className: "Workers")
query.findObjectsInBackground(block: { (objects1, error) in
if error != nil {
print(error!)
} else {
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (objects2, error) in
for object in objects2! {
self.cellContent.append(object["workerName"] as! String)
self.cellContent.sort()
self.tableView.reloadData()
}
}
)}
}
)}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
cellContent.remove(at: indexPath.row)
tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
segueWorker = (currentCell.textLabel!.text!)
performSegue(withIdentifier: "toAddWorkers", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Took some tinkering but finally got it to work by spreading out the variables and finally building the dictionary once I had all variables created. Also, had a lot of trouble with getting the objectId from Parse but seems to be working by simply calling object.objectId.
Code below for reference:
self.cellContent.removeAll()
let query = PFQuery(className: "Workers")
query.findObjectsInBackground(block: { (objects1, error) in
if error != nil {
print(error!)
} else {
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (objects2, error) in
for object in objects2! {
self.cellContent.append(object["workerName"] as! String)
// Needs to be objectId
let objectKey = object.objectId
let objectValue = object["workerName"] as! String
self.cellContentDict[objectKey!] = objectValue
print(self.cellContentDict)
self.cellContent.sort()
self.tableView.reloadData()

How to get Label text of UITableView Cell using Swift?

I want to make simple UITabelView. I registered it's cell with my custom class which named as backgroundviewcell. I want to get Label of the selected cell. I tried many times but the output is coming nil value. I have also tried solution from stack overflow but it does not work for me. This is my cellForRowAt indexPath code :
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> backgroundViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "soundElementalcell") as! backgroundViewCell
let imageNames = sections[indexPath.section].images[indexPath.row]
cell.Labeltittle.text = sections[indexPath.section].items[indexPath.row]
cell.Labeltittle.textColor = UIColor(hex : 0x90BA27)
cell.LabelDetail.text = sections[indexPath.section].detail[indexPath.row]
//cell.detailTextLabel?.textColor = UIColor.red
//cell.isHighlighted = false
cell.backgroundColor = UIColor.clear
cell.iconview.image = UIImage(named: imageNames)
return cell
}
This is my didSelectRowAt indexPath code :
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)!
celltext = currentCell.textLabel!.text
performSegue(withIdentifier: "showPlayer", sender: self)
}
and my Segue Method is :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPlayer" {
let playerVC = segue.destination as! PlayerViewController
playerVC.trackName = (celltext)! as String
}
}
This is working for me:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! YourCellType
let labelContent = cell.labelToAccess.text
}
First line creates an instance of your cell type (or standard cell, not my case).
The second saves the content of your label (labelToAccess in this case) in a constant.
Instead of accessing the text from the cell's label you need to access the array that you have used to fill the tableView's cell data.
So you need to use UITableViewDelegate method didSelectRowAtindexPath and access the array that you are using with your tableView methods.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
//Access the array that you have used to fill the tableViewCell
print(yourArray[indexPath.row])
}
Note: Once confirm that TableView delegate is properly connected with your ViewController so that it will call didSelectRowAt method when you select cell.
Edit: If you want to pass the data then try like this way.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showPlayer", sender: indexPath) //Pass indexPath as sender instead of self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPlayer" {
let playerVC = segue.destination as! PlayerViewController
let indexPath = sender as! IndexPath
playerVC.trackName = sections[indexPath.section].items[indexPath.row]
}
}
Try this 'Swift 4' -
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCellTxt = yourTableView.cellForRow(at: indexPath)! as? YourCustomTableViewCell
print(currentCellTxt?.lblYourName?.text) // 'lblYourName' that you defined in your 'YourCustomTableViewCell'
}
You didn't set any text for textLabel. Hence it returns nil value.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> backgroundViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "soundElementalcell") as! backgroundViewCell
let imageNames = sections[indexPath.section].images[indexPath.row]
cell.Labeltittle.text = sections[indexPath.section].items[indexPath.row]
cell.Labeltittle.textColor = UIColor(hex : 0x90BA27)
cell.LabelDetail.text = sections[indexPath.section].detail[indexPath.row]
//cell.detailTextLabel?.textColor = UIColor.red
//cell.isHighlighted = false
cell.backgroundColor = UIColor.clear
cell.iconview.image = UIImage(named: imageNames)
return cell
}
In didSelectRow func try to get value from Labeltittle.text not from textLabel.text
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)!
celltext = currentCell.Labeltittle.text
performSegue(withIdentifier: "showPlayer", sender: self)
}

Load table with titles from JSON

I have a page with a TableView that fills each cell with a hardcoded UILabel of some text. I would like it to fill up with UILabels from a JSON that I get online.
Storyboard:
The code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var objects: NSMutableArray! = NSMutableArray()
override func viewDidLoad(){
super.viewDidLoad()
self.objects.add("iPhone")
self.objects.add("Apple Watch")
self.objects.add("Mac")
self.objects.add("Test")
self.tableView.reloadData()
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(_ tableView: UITableView) -> Int{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.objects.count
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.titleLabel.text = self.objects.object(at: (indexPath as NSIndexPath).row) as? String
//cell.logButton.tag = (indexPath as NSIndexPath).row;
//cell.logButton.addTarget(self, action: #selector(ViewController.logAction(_:)), for: .touchUpInside)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath){
self.performSegue(withIdentifier: "showView", sender: self)
}
#IBAction func logAction(_ sender: UIButton) {
let titleString = self.objects[sender.tag] as? String
let firstActivityItem = "\(titleString!)"
let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if (segue.identifier == "showView"){
let upcoming: NewViewController = segue.destination as! NewViewController
let indexPath = self.tableView.indexPathForSelectedRow!
let titleString = self.objects.object(at: indexPath.row) as? String
upcoming.titleString = titleString
self.tableView.deselectRow(at: indexPath, animated: true)
}
}
}
Once in simulator and I open up the page, the TableView will have four cells with the "Label" changing to whatever was adding to the objects array, which in this case is iPhone, Apple Watch, Mac, and Test. Rather than having those hardcoded, I would like to have the items loaded from a JSON file.
I have the same thing done with a PickerView, but I am struggling to figure out how to do it with this. Here is how it was done with my PickerView if it helps:
Alamofire.request("example.com/file.json").responseJSON{ response in
if let JSON = response.result.value as? [String:AnyObject] {
self.mypickerview.delegate = self
self.mypickerview.dataSource = self
let result = JSON.values.flatMap({ String(describing: $0) })
self.pickerData.append(contentsOf: result)
self.pickerData.sort()
self.verbose.text = "Content saved!"
self.mypickerview.reloadAllComponents()
self.mypickerview.delegate = self;
self.verbose.text = "Finished Loading!"
}
}
The JSON file:
{"One":"Mac","Two":"Apple iPhone","Three":"Test"}
1.On viewDidLoad fire the webService.
2.On Webservice completion handler ,retreive the label values and assign to objects.
3.Reload tableview.
your JSON should look like this:
{
"titles": [
"mac",
"iphone",
"test"
]
}
and you will do something like cell.titleLabel.text = [[yourJSON valueForKey:#"titles"] objectAtIndex:indexPath.row];
(this is Obj-C version, but ofc it can be done also in swift)

Resources