Swift- passing data from a multiple-section tableview to ViewController - ios

I have a two-section tableview (see image below)
When I click row "A", another tableview shows up with letter "A"
When I click row "B", another tableview shows up with letter "B"
How can I pass the letter "C" to another tableview when I click row C ?
Here's my code in TableView:
import UIKit
class manhinh1: UITableViewController {
var UserDefault:NSUserDefaults!
var array:[[String]]!
override func viewDidLoad() {
super.viewDidLoad()
UserDefault = NSUserDefaults()
array = [["A","B"],["C","D","E"]]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return array.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
if section == 0 {
return array[0].count
}
if section == 1 {
return array[1].count
}
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
if indexPath.section == 0 {
cell.textLabel?.text = array[0][indexPath.row]
}
if indexPath.section == 1 {
cell.textLabel?.text = array[1][indexPath.row]
}
// Configure the cell...
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var row = self.tableView.indexPathForSelectedRow()!.row
UserDefault.setObject(array[0][row], forKey: "selected")
}
}
Here's the code in second view:
import UIKit
class ViewController: UIViewController {
var UserDefault:NSUserDefaults!
#IBOutlet weak var lbldata: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
UserDefault = NSUserDefaults()
// Do any additional setup after loading the view, typically from a }
lbldata.text = UserDefault.objectForKey("selected") as! String
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I did try a few code in prepareForSegue, but it didn't work. I hope you guys can show me a way. Thanks

You have to get the row and the section to access your multidimensional array. Then get the destination view controller of your segue and assign the corresponding value from the array to the UserDefault property:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var row = self.tableView.indexPathForSelectedRow()!.row
var section = self.tableView.indexPathForSelectedRow()!.section
var destinationViewController = segue.destinationViewController as! ViewController
destinationViewController.UserDefault.setObject(array[section][row], forKey: "selected")
}

Related

Append array from another Controller

I want to append new element to array. I'm using container view. I call addItem function to tableviewcontroller. But I clicked button nothing happen.
My TableViewController
import UIKit
class TableViewController: UITableViewController {
var myArray = ["1"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func addItem () {
myArray.append("asd")
tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return myArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel?.text = myArray[indexPath.row]
return cell
}
}
My TableViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addButton(sender: AnyObject) {
TableViewController().addItem()
}
}
The line TableViewController().addItem() means create a brand new instance of TableViewController and then call addItem() on it. You need to find a reference to the specific instance of TableViewController you want to manipulate. How does that ViewController relate to the one calling addItem?
It should be something like this:
class ViewController: UIViewController {
let tableViewController = TableViewController()
..
#IBAction func addButton(sender: AnyObject) {
tableViewController.addItem()
}
}

Swift: Passing data from a tableView in a ViewController to another ViewController

I'm trying to pass the indexPath.row data from the selected cell to the next view controller using both the didSelectCellAtIndexPath and the prepareForSegue methods but the value isnt passing through.
Code for both ViewControllers is show below:
import UIKit
class MainMenu: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
// array of the menu options
let mainMenuOptions = ["Exercises 1", "Exercises 2", "Exercises 3"]
// UITableView
#IBOutlet weak var exerciseOptions: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
exerciseOptions.delegate = self
exerciseOptions.dataSource = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Table configuration
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ExercisesTableViewCells"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ExercisesTableViewCell
cell.textLabel!.text = mainMenuOptions[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
// Segue to VC based on row selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0{
self.performSegueWithIdentifier("SegueToExercises", sender: self)
}
else if indexPath.row == 1{
self.performSegueWithIdentifier("SegueToExercises", sender: self)
}
else{
self.performSegueWithIdentifier("SegueToReminders", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToExercise"){
let viewController = segue.destinationViewController as? ExerciseMenu
viewController!.mainMenuValue = exerciseOptions.indexPathForSelectedRow!.row
}
}
For the Second View Controller:
import UIKit
class ExerciseMenu: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var exerciseOptionsTitle: UILabel!
#IBOutlet weak var exerciseOptionsTable: UITableView!
#IBAction func beginWorkout(sender: AnyObject) {
}
// receives data from MainMenu
var mainMenuValue: Int!
override func viewDidLoad() {
super.viewDidLoad()
exerciseOptionsTable.delegate = self
exerciseOptionsTable.dataSource = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ExerciseMenuCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ExercisesTableViewCell
cell.textLabel!.text = String(mainMenuValue)
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
See this thread for possible explanations for this behavior.
The first step of troubleshooting would be to put a breakpoint in your prepareForSegue method to see if exerciseOptions.indexPathForSelectedRow is already nil at that point, in which case something is happening before the segue even occurs that's messing with the value (which the link above can help you diagnose).
Try making a property in your table view controller called something like selectedRow, and in didSelectRowAtIndexPath, set self.selectedRow = indexPath.row. This way you have your own variable that'll be more reliable than exerciseOptions.indexPathForSelectedRow. Then change the code in prepareForSegue appropriately. So to give you the full methods as I'm envisioning them:
(As a property of the first view controller) var selectedRow: Int?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0{
self.performSegueWithIdentifier("SegueToExercises", sender: self)
self.selectedRow = 0
}
else if indexPath.row == 1{
self.performSegueWithIdentifier("SegueToExercises", sender: self)
self.selectedRow = 1
}
else{
self.performSegueWithIdentifier("SegueToReminders", sender: self)
self.selectedRow = indexPath.row
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToExercise"){
let viewController = segue.destinationViewController as? ExerciseMenu
viewController!.mainMenuValue = self.selectedRow!
}
}
Disclaimer: I'm still learning Swift, so my judgment regarding optionals/optional unwrapping might be unideal for a technical reason I'm not aware of, but the overall theory here is sound, I think.

PFQuery first returning 6 items then 3 in a UITableViewController

He everyone,
Im pulling my hears out for a whole day for the following issue. My back-end is in Parse and i am doing a query on my table "events" in a UITableViewController. The problem is that the query returns the complete data in the ViewDidLoad but not in my tableView method. In my tableView im only getting 3 items returned. Im aware of that parse query doing a Asynchronously call but why its returning 3 items?
I would be gratefull if somebody can help me out here.
Here is my code:
class EventOverViewController: UITableViewController {
var events:Array = [AnyObject]();
var imageContainer : UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
self.retrieveInfoFromParse();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.events.count
}
func queryForTable() -> PFQuery {
let getEvents = PFQuery(className:"Event");
return getEvents;
}
func retrieveInfoFromParse(){
self.queryForTable().findObjectsInBackgroundWithBlock { (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
self.events.append(object);
}
//RETURNING 6 ITEMS
print(self.events);
self.tableView.reloadData();
}
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 230;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("EventCell", forIndexPath:indexPath) as! EventTableViewCell
let eventData = self.events[indexPath.row];
//ONLY returning 3 ITEMS, WHY?
print(eventData);
return cell
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow!
let destinationVC = segue.destinationViewController as! RootMainViewController
var secondEventData : Event!
secondEventData = self.events[indexPath.row] as! Event;
destinationVC.title = secondEventData.eventName;
destinationVC.event = secondEventData;
}
}

How to get a UITableView method to run before another override method?

Below is my code. After testing the app for a bit I realized that the didSelectRowAtIndex is run AFTER prepareForSegue. How can I get didSelectRowAtIndex to run first.
If the answer involves threading, I have no idea how that works so please explain. Thank-you.
import UIKit
class AvailableShifts: UITableViewController {
var shiftData: NSMutableArray = NSMutableArray()
var shiftID: String!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
// self.refreshControl = UIRefreshControl()
//
// self.refreshControl?.addTarget(self, action: "refreshList", forControlEvents: .ValueChanged)
loadData()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return shiftData.count
}
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {
let cell:AvailableShiftsCell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath!) as AvailableShiftsCell
let shift: PFObject = shiftData.objectAtIndex(indexPath!.row) as PFObject
cell.locationLabel.text = shift.objectForKey("Location") as String?
cell.shiftLabel.text = shift.objectForKey("Shift") as String?
cell.dateLabel.text = shift.objectForKey("Date") as String?
cell.id.text = shift.objectId
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let shift: PFObject = shiftData.objectAtIndex(indexPath.row) as PFObject
shiftID = shift.objectId
println(shiftID)
}
func loadData () {
var getShifts = PFQuery(className: "Shifts")
getShifts.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if (error == nil) {
self.shiftData.removeAllObjects()
for object in objects {
self.shiftData.addObject(object)
}
let array: NSArray = self.shiftData.reverseObjectEnumerator().allObjects
self.shiftData = array.mutableCopy() as NSMutableArray
self.tableView.reloadData()
}
}
}
#IBAction func refreshButtonPressed(sender: AnyObject) {
loadData()
}
// func refreshList() {
//
// loadData()
//
// self.refreshControl?.endRefreshing()
//
// }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "details") {
var svc = segue.destinationViewController as ShiftOverview;
svc.shiftID = shiftID
println(shiftID)
}
}
}
There's no need to implement didSelectRowAtIndexPath at all for your application. If the segue is made from the cell, then the sender argument in prepareForSegue:sender: will be the cell. You can use the table view method indexPathForCell: to get the indexPath, and thus the PFObject you need.

delegate modal view swift

I have tried the other methods for delegation and protocols for passing data between modal views and the parent view button they aren't working for me. This is obviously because I am implementing them wrong.
What I have is a parent view controller which has a tableviewcell which in the right detail will tell you your selection from the modal view. The modal view is another table view which allows you to select a cell, which updates the right detail and dismisses the modal view. All is working except the actual data transfer.
Thanks in advance!! :)
Here is my code for the parent view controller:
class TableViewController: UITableViewController, UITextFieldDelegate {
//Properties
var delegate: transferData?
//Outlets
#IBOutlet var productLabel: UILabel!
#IBOutlet var rightDetail: UILabel!
override func viewWillAppear(animated: Bool) {
println(delegate?.productCarrier)
println(delegate?.priceCarrier)
if delegate?.productCarrier != "" {
rightDetail.text = delegate?.productCarrier
productLabel.text = delegate?.productCarrier
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 5
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return 1
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
The code for the model view controller and protocol is:
protocol transferData {
var priceCarrier: Double { get set }
var productCarrier: String { get set }
}
class ProductsDetailsViewController: UITableViewController, transferData {
//Properties
var priceCarrier = 00.00
var productCarrier = ""
//Outlets
//Actions
#IBAction func unwindToViewController(segue: UIStoryboardSegue) {
self.dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
populateDefaultCategories()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return Int(Category.allObjects().count)
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return (Category.allObjects()[UInt(section)] as Category).name
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return Int(objectsForSection(section).count)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:ProductListCell = tableView.dequeueReusableCellWithIdentifier("productCell", forIndexPath: indexPath) as ProductListCell
let queriedProductResult = objectForProductFromSection(indexPath.section, indexPath.row)
cell.name.text = queriedProductResult.name
cell.prices.text = "$\(queriedProductResult.price)"
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = self.tableView.indexPathForSelectedRow()!
let product = objectForProductFromSection(indexPath.section, indexPath.row)
let PVC: TableViewController = TableViewController()
println("didSelect")
productCarrier = product.name
priceCarrier = product.price
println(productCarrier)
println(priceCarrier)
self.dismissViewControllerAnimated(true, completion: nil)
}
I think for passing data, you should use segue like:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = self.tableView.indexPathForSelectedRow()!
let product = objectForProductFromSection(indexPath.section, indexPath.row)
println("didSelect")
productCarrier = product.name
priceCarrier = product.price
println(productCarrier)
println(priceCarrier)
self.performSegueWithIdentifier("displayYourTableViewControllerSegue", sender: self)
}
and then override the prepareForSegue function:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var controller = segue.destinationViewController as TableViewController
controller.rightDetail.text = "\(self.priceCarrier)"
controller.productLabel.text = self.productCarrier
}

Resources