Passing data into UITableView - swift

I am new to swift and have been experimenting with passing data between view controllers. I have been attempting to pass data from a view controller into a UITableViewCell, However once run my code has no effect.
DetailViewController
(passes data to the libraryViewController)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: LibraryMovieViewController = segue.destination as! LibraryMovieViewController
DestViewController.movieTitle = movieTitle
DestViewController.movieRelease = movieReleaseDate
}
}
UITableViewCell
class MovieSearchTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var posterView: UIImageView!
#IBOutlet weak var overviewLabel: UILabel!
}
LibraryViewController
struct libMovie {
//let mainImage: UIImage
let title: String
let release: String
}
class LibraryMovieViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dataSource: [libMovie] = []
var movieTitle: String!
var movieRelease: String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
// Do any additional setup after loading the view.
loadDataSource()
}
func loadDataSource(){
// dataSource.append(libMovie(title: " \(movieTitle)", release: " \(movieRelease)"))
}
}
extension LibraryMovieViewController: UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 115
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let movieCell = tableView.dequeueReusableCell(withIdentifier: "libCell", for: indexPath) as? LibraryMovieTableViewCell else {
return UITableViewCell()
}
let libMovie = dataSource[indexPath.row]
movieCell.cellTitleLabel.text = "Movie Title: \(movieTitle)"
movieCell.cellReleaseLabel.text = "Release Date: \(movieRelease)"
return movieCell
}
}
I would expect that when the app is run that movieTitle and movieReleaseDate are passed from the detail view controller and input into the library table cell, this is initiated by tapping a button on the detail view controller.
However this seems to have no affect on the program or simply returns blank cells.
No errors are reported in console nor does the app crash

In prepareForSegue you've passed data to movieTitle and movieRelease, while you're using dataSource to inflate data on tableView.
Either pass and object of [libMovie] to DestViewController.dataSource if you want to inflate multiple rows of different movies or return 1 in numberOfRowsInSection and pass set the label content in cell with movieTitle and movieRelease.

In your code, numberOfRowsInSection is returning dataSource.count, but doesn't seem to pass that data to this view controller.
You can either hardcode the numberOfRowsInSection as 1 or pass the dataSource from the first view controller and update your cellForRowAtIndexPath method.

The data source in the destination view controller is empty, what do you expect?
Uncomment the line in loadDataSource and reload the table view.
func loadDataSource(){
dataSource.append(ibMovie(title: movieTitle, release: movieRelease))
tableView.reloadData()
}
And replace
movieCell.cellTitleLabel.text = "Movie Title: \(movieTitle)"
movieCell.cellReleaseLabel.text = "Release Date: \(movieRelease)"
with
movieCell.cellTitleLabel.text = "Movie Title: \(libMovie.title)"
movieCell.cellReleaseLabel.text = "Release Date: \(libMovie.release)"

Related

How to get value from table view cell

I need to take price from table view cell
I need to get it another VC
I need to transfer price each time when user selected row
The problem is that I don't know how correctly get the value from tableView
MenueViewController:
import UIKit
class MenueViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dishes: [Dish] = []
var totalSum = 0
override func viewDidLoad() {
super.viewDidLoad()
dishes = createArray()
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = .white
navigationItem.title = "Меню"
}
func createArray() -> [Dish] {
var tempDishes: [Dish] = []
let dish1 = Dish(image: UIImage.init(named: "plovKebab")!, title: "Плов Кебаб", price: 169, type: "Основные Блюда")
let dish2 = Dish(image: UIImage.init(named: "plovKebabShafran")!, title: "Плов Кебаб Шафран", price: 169, type: "Основные Блюда")
tempDishes.append(dish1)
tempDishes.append(dish2)
return tempDishes
}
}
extension MenueViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dishes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let dish = dishes[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "MenueCell") as! MenueCell
cell.setDish(dish: dish)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dish = dishes[indexPath.row]
totalSum += dish.price //the place where I tried to take price
print(totalSum)
}
}
VC where we need to take that price:
import UIKit
class OrderViewController: UIViewController {
#IBOutlet weak var totalPriceLabel: UILabel!
var totalPrice: MenueViewController?
var sum:Int?
override func viewDidLoad() {
super.viewDidLoad()
if let price = sum {
totalPriceLabel.text = String(totalPrice?.totalSum)
}
}
The value of sum is 0
How can I get the value?
Please note that the didSelectRowAtIndexpath will not get called before your performSegue. At this link, you can find a detailed explanation including a sample code about your problem and how it can be solved.
Also, there are multiple approaches listed below to solve your problem.
Use willSelectIndexpath and capture the indexpath to pass it in performSegue method
Use didSelectIndexpath and perform segue inside
Use only didSelectIndexpath and perform the navigation logic inside it with out segues

Aftar i click on cell its pass me 2 views, how can i fix it?

I have an app that starts with tab bar with 3 items,2 of them is just a regular view controller and one of them is navigation controller and after him is table view,when I click on a cell I want to pass 2 String to the labels and to pass to a new view controller to show the label's,my problem is that after I click on the cell its looks like its jump 2 view controller's until the view controller that I want, and in the first time I didn't see my data that I pass, only after I press to come back to the table view controller(here I need to back to him from 2 view controllers), please help me to fix my code, I want to pass the data and move to a new view controller and when I want to come back to the table view I need to click just back
//Table view controller, before of him I have a navigation controller
//The identifier of the segue is "Details"
import UIKit
class HistoryTableViewController:
UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var historyTableView: UITableView!
var historyArray = [history]()
var foods = ["Milk","Honey","Salt","Bread","Banana"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foods.count
//historyArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = historyTableView.dequeueReusableCell(withIdentifier: "cell") as? HistoryCellViewController
else {return UITableViewCell()}
// cell.ageLabel.text = String(format:"%f", historyArray[indexPath.row].age)
// cell.genderLabel.text = historyArray[indexPath.row].gender
// cell.ageLabel.text = String(format:"%f", 23)
cell.genderLabel.text = foods[indexPath.row]
cell.ageLabel.text = foods[indexPath.row]
// cell.genderLabel.text = "Bar"
//cell.historyImage.image = nil
return cell
}
var selectedAge:String = " "
var selectedGender:String = " "
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedAge = self.foods[indexPath.row]
selectedGender = self.foods[indexPath.row]
performSegue(withIdentifier: "Details", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Details"{
let vc = segue.destination as! HistoryDetailsViewController
vc.age = selectedAge
vc.gender = selectedGender
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
foods.remove(at: indexPath.row)
historyTableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
//view controller that I want to pass after a click on a cell
import UIKit
class HistoryDetailsViewController: UIViewController {
#IBOutlet weak var ageLabel: UILabel!
#IBOutlet weak var genderLabel: UILabel!
var age:String?
var gender:String?
override func viewDidLoad() {
super.viewDidLoad()
ageLabel.text = self.age
genderLabel.text = self.gender
// Do any additional setup after loading the view.
}
//
// #IBAction func Back(_ sender: UIBarButtonItem) {
//
// // self.tabBarController?.selectedIndex = 0
// }
}
First of all, in tableView(_:cellForRowAt:) you're typecasting the dequeued cell to HistoryCellViewController.
My question is - what is the type of HistoryCellViewController? Is it a UITableViewCell or something else? In case it is a UITableViewCell you must rename it to something more relevant like HistoryCell. It is a bit confusing.
Approach-1:
Now coming to the actual problem you're facing. Instead of using the segue, try pushing the HistoryDetailsViewController manually like so,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let controller = self.storyboard?.instantiateViewController(withIdentifier: "HistoryDetailsViewController") as? HistoryDetailsViewController {
controller.age = self.foods[indexPath.row]
controller.gender = self.foods[indexPath.row]
self.navigationController?.pushViewController(controller, animated: true)
}
}
There is no need to extra variables - selectedAge and selectedGender.
Approach-2:
In case you want to do it with the segue itself, then don't call performSegue(withIdentifier:sender:) in tableView(_:didSelectRowAt:), i.e. remove the below line of code,
performSegue(withIdentifier: "Details", sender: self)
This is because, the "Details" segue is being executed twice - once via storyboard and another via the above line of code.

My TableView's not changed after reload data

I wrote a class that let me create multiple tableView simply. When I call this class for the first time, everything work well. But when I change some data, and reload the table, nothing changed.
Sample code:
class TestViewController: UIViewController {
var arrData = ["a","b","c"]
var myTableView: MyTableView?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myTableView = MyTableView(table: tableView, data: arrData)
}
#IBAction func buttonTapped(_ sender: UIButton) {
arrData = ["d","e","f"]
myTableView!.tableView.reloadData() //=> Not change anything
}
}
class MyTableView: NSObject, UITableViewDataSource {
var tableView: UITableView
var data: Array<String>
init(table: UITableView, data: Array<String>) {
self.data = data
self.tableView = table
super.init()
self.tableView.dataSource = self
self.tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "myCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
cell.textLabel!.text = self.data[indexPath.row]
return cell
}
}
class MyTableViewCell : UITableViewCell {
//something here
}
When the view was loaded, the table has 3 rows: a,b,c. When I tap the button, nothing changed (expected: d,e,f)
Please help me!
Swift arrays are copied by value so the line self.data = data will take a copy of your array. Later changing the array contents of the source will not be reflected in the copy in your MyTableView.
You'll need to pass the array over again and take a second copy to update the table, e.g. write a method in MyTableView similar to the following:-
func setNewValues(data: Array<String>)
{
self.data = data
self.tableView.reloadData()
}
and call that from your buttonTapped function, i.e.:
#IBAction func buttonTapped(_ sender: UIButton) {
arrData = ["d","e","f"]
myTableView!.setNewValues(data: arrData)
}
Be careful with the force-unwrapped myTableView though - I'd replace that '!' with '?'.

swift - embedded SWRevealViewController to you application

I intergrade SWRevealViewController to my project
my project flow is
viewcontroller ---> SWRevealViewController -->menu
--> nav-->front view
the segue method from my initial view controller to SWRevealViewController is model
my problem is when my I open toggle in front view for first time only
it give me empty menu(table view)
my front view code
#IBOutlet weak var open: UIBarButtonItem!
#IBOutlet weak var result: UILabel!
#IBAction func showmore(sender: AnyObject) {
performSegueWithIdentifier("resdes", sender: sender)
}
override func viewDidLoad() {
super.viewDidLoad()
var res = Uti.get_result()
result.text = res.description
open.target = self.revealViewController()
open.action = Selector("revealToggle:")
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
// Do any additional setup after loading the view.
}
my rear code
class slidemenuVC : UITableViewController{
var menuItems = [String]()
override func viewDidAppear(animated: Bool) {
menuItems = ["Result","About us","References","Rest Test"]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(menuItems[indexPath.row], forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = menuItems[indexPath.row]
return cell
}
}
Second problem :
when I press at first menu item , navigation disappear
it should be like this have toggle
var cell = tableView.dequeueReusableCellWithIdentifier(menuItems[indexPath.row], forIndexPath: indexPath) as UITableViewCell
is wrong. You need your identifier has to be the actual cell id in your uitableviewcell

Changing Labels in DetailVC from tableView

I’m trying to make changes to a label in a DetailViewController, depending on which row we click:
That is how my test App looks
For example, if we click Ferrari I want to display:
“Wow , it's a beautiful red Ferrari of the year… blablabla..”
But if you click another instead:
“I’m the label of the…. car”
Essentially, one description for each car.
How do I change the label?
My code :
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var valueToPass : String!
//crear un color
let medOrange: UIColor = UIColor(red: 0.973, green: 0.388, blue: 0.173, alpha: 1)
var vehicleData : [String] = ["Ferrari 458" , "Lamborghini Murcielago" , "Bugatti Veyron", "Mercedes Benz Biome"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var nib = UINib(nibName: "TableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
//Propiedades de la tableView
self.tableView.backgroundColor = medOrange
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vehicleData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:TableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as TableViewCell
cell.lblCarName.text = vehicleData[indexPath.row]
cell.imgCar.image = UIImage(named: vehicleData[indexPath.row])
cell.backgroundColor = medOrange
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("Has seleccionado la celda #\(indexPath.row)!")
//Obtener la label de la celda
let indexPath = tableView.indexPathForSelectedRow()
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
valueToPass = currentCell.textLabel?.text
performSegueWithIdentifier("DetailView", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "DetailView") {
var vc = segue.destinationViewController as DetailViewController
vc.passedValue = valueToPass
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
import UIKit
class DetailViewController: UIViewController {
var passedValue : String!
#IBOutlet weak var lblDetail: UILabel!
#IBOutlet weak var imgDetail: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
From what I can see you did all well and the only part missing in your code is setting passedValue to label in your DetailViewController so just add the following in viewDidLoad method
override func viewDidLoad() {
super.viewDidLoad()
lblDetail.text = passedValue
}
EDITED:
To pass description to DetaliViewContorller you have to store it somehow first and the best way to do it is by declaring a struct that holds both name and description
struct Vehicle {
var vehicleName : String
var vehicleDescription : String
}
Then your vehicleData array should contain objects of type Vehicle
var vehicleData : [Vehice] = [Vehicle(vehicleName : "Ferrari 458",vehicleDescription : "Ferrari desc" ), //Add all vehicles like this...]
And finally passedValue must be initialized like this
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
valueToPass = vehicleData[indexPath.row].vehicleDescription
performSegueWithIdentifier("DetailView", sender: self)
}
its Simple do the following steps:
add one more array with the details text in the details view controller.
when user click on the row you need to get the index.row and pass it to your details view controller.
retrive data from your number 1 step array using index path.
add it to your Lable.
and must set your Lable.text in the ViewDidLoad method.