I can't get a simple segue to work when a cell in a tableview gets pressed. It does go to the next view after I tapped two different items. But I can't pass any values from the first controller to the second. If I set a value to the label in the second controller and load it in the viewDidLoad method it shows up.
I'm going crazy as I've been trying to get this work for ages....
My storyboard: https://snag.gy/DCw9MU.jpg
CategoryListViewController(1st controller):
import Foundation
import UIKit
class CategoryListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var categoryList = TestData.sharedInstance.categoryList
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "iEngineer"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tableView .reloadData()
tableView.dataSource = self
for category in categoryList{
print(category)
}
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showFormulaList" {
if let indexPath = tableView.indexPathForSelectedRow {
let category = self.categoryList[indexPath.row]
let formulaListViewController = (segue.destination as! UINavigationController).topViewController as! FormulaListViewController
formulaListViewController.text = category
formulaListViewController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
formulaListViewController.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(categoryList.count)
return categoryList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "categoryCell", for: indexPath)
let object = categoryList[indexPath.row]
cell.textLabel!.text = object
return cell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: self)
}
}
FormulaListViewController(2nd controller):
import Foundation
import UIKit
class FormulaListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var titleLabel: UILabel!
var formulaList = TestData.sharedInstance.formulaList
var fSwift: String!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "iEngineer"
print(fSwift)
titleLabel.text = fSwift
}
// MARK: - Table View
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(formulaList.count)
return formulaList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "formulaCell", for: indexPath)
let object = formulaList[indexPath.row]
print(object)
cell.textLabel!.text = object
return cell
}
}
Where is my mistake or what am I doing wrong?
I greatly appreciate any help
You need didSelectRowAt instead of didDeselectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: self)
}
Also make sure segue source is the vc not the cell , and since you fire the segue in didDeselectRowAt this
if let indexPath = tableView.indexPathForSelectedRow
will be nil
You have used didDeselectRowAt:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: self)
}
You need to use didSelectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: self)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: self)
}
You should use didSelect instead of didDeselectRowAt, also you should pass something better than self, because with self you are passing the entire CategoryListViewController
Try to pass the indexPath like this
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFormulaList", sender: indexPath)
}
and change the function prepare in this
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showFormulaList" {
if let indexPath = sender as? IndexPath {
let category = self.categoryList[indexPath.row]
let formulaListViewController = (segue.destination as! UINavigationController).topViewController as! FormulaListViewController
formulaListViewController.fuckSwift = category
formulaListViewController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
formulaListViewController.navigationItem.leftItemsSupplementBackButton = true
}
}
}
If this doesn't help you try to debug your code and find where you lost your variable :)
Related
I'm having difficulty with passing a realm object's data from a tableViewController to a viewController. I want to choose one of the objects from the table and have that object's data be used in the following viewController. I've struggled to find resources here which deal with Realm objects instead of just passing strings and the likes. Any assistance would be great.
Here's my TableViewController with my attempt at creating a segue function to the second view :
class WorkoutController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DBHelper.shared.getWorkout().count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
let muscle = DBHelper.shared.getWorkout()[indexPath.row]
cell.textLabel?.text = muscle
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let workoutDetailVC = segue.destination as! WorkoutDetail
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let name = DBHelper.shared.getWorkout()[indexPath.row]
workoutDetailVC.receivedName = name
}
}
}
Here's the WorkoutDetail class which is supposed to receive and show the data :
class WorkoutDetail: UIViewController {
#IBOutlet weak var muscleLabel: UILabel!
var receivedName = ""
override func viewDidLoad() {
super.viewDidLoad()
muscleLabel.text = receivedName
}
}
Here is the getWorkout() function referenced above :
func getWorkout()-> [String] {
var musclesName = [String]()
let storedExercise = realm.objects(Workout1.self)
for exercise in storedExercise {
musclesName.append(exercise.exercise)
}
return musclesName
}
I'm having real difficulty with this and would very much appreciate some assistance, thanks.
Get didSelectRowAt out of prepare then
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
let muscle = DBHelper.shared.getWorkout()[indexPath.row]
cell.textLabel?.text = muscle
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let name = DBHelper.shared.getWorkout()[indexPath.row]
self.performSegue(withIdentifier:"SegueName",sender:name)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let workoutDetailVC = segue.destination as! WorkoutDetail
workoutDetailVC.receivedName = sender as! String
}
Choosing a string in a UITableViewController, shows pic of the same name in another view controller, which works as it should.
But the problem is when I want to choose multiple strings to show multiple different pics.
I've been trying to add another IBOutlet, doubling stuff, but it was just showing me the same pic twice.
Any idea?
multiple selection = true
First VC segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "tablesegue" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedRow = indexPath.row
let passingVal = segue.destination as! Tabulka_data
passingVal.selectedImageName = self.tableItems[selectedRow]
}
}
}
secondVC:
#IBOutlet weak var pic: UIImageView!
var selectedImageName:String = ""
override func viewWillAppear(_ animated: Bool) {
self.pic.image = UIImage(named: selectedImageName)
}
two choices
You can try this
let yourDataArray = ["name 1","name 2","name 3","name 4","name 5"]
var imageSelected = [String]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourDataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = yourTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = yourDataArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
imageSelected.append(yourDataArray[indexPath.row])
print(imageSelected)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
for (index, element) in imageSelected.enumerated() {
if element == yourDataArray[indexPath.row] {
imageSelected.remove(at: index)
}
}
print(imageSelected)
}
You can use didSelectRowAt and didDeoRowAt to see which rows are selected, then just pass imageSelected to the second viewController
I have already shown a list of metro station on the screen, what I want to do is when clicking different stations, they can pass their information to the second tableview and display, how to do that by using segue and didselectRowAt?
tablecell class
class LandmarksTableViewCell: UITableViewCell {
#IBOutlet weak var LandmardsImage: UIImageView!
#IBOutlet weak var LandmarksLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
metrostationViewController
class MetroStationsViewController: UITableViewController{
let wmataapimanager = WmataAPIManager()
let locationDetector = LocationDetector()
var stations = [Station](){
didSet{
tableView.reloadData()
}
}
var landmarks = [Landmark]()
override func viewDidLoad(){
super.viewDidLoad()
wmataapimanager.delegate = self as FetchStationsDelegate
locationDetector.delegate = self as LocationDetectorDelegate
fetchStation()
}
private func fetchStation(){
locationDetector.findLocation()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "StationCell", for: indexPath) as! StationsTableViewCell
let station = stations[indexPath.row]
cell.StationLabel.text = station.name
//cell.LaiLabel.text = String(station.Lat)
//cell.LonLabel.text = String(station.Lon)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("you select: \(indexPath.row)")
let selectStation = stations[indexPath.row]
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
}
}
In didSelectRowAt delegate method perform segue and as sender pass selected station
performSegue(withIdentifier: "identifier", sender: stations[indexPath.row])
then you should have variable in destination ViewController and you can assign this variable in prepare for segue method as downcasted sender
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "identifier" {
let destinationVC = segue.destination as! DestinationViewController
destinationVC.station = sender as! Station
}
}
JSON data is already alphabetized before being downloaded. The app correctly divides the data into sections, creates the section title based off of the first letter, and lists all names starting with that letter in the correct section. The problem is each section repeats the same data once it transitions to the detail view controller. Sections B, C, etc. show all of correct names but repeat the "A" names when going to the detail view controller. How can I get the selected cell and the details view controller to match again?
func numberOfSections(in tableView: UITableView) -> Int {
return figuresByLetter.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return figuresByLetter[section].key
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return figuresByLetter[section].value.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "figureCell", for: indexPath)
cell.textLabel?.text = figuresByLetter[indexPath.section].value[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? FigureViewController {
destination.figure = figures[(tableView.indexPathForSelectedRow?.row)!]
}
}
Let me know if there is any other code needed to answer the question!
struct FigureStats: Decodable {
let name: String
let number: String
let weapon: String?
let desc: String?
let year: String?
}
In the detail view controller:
class FigureViewController: UIViewController {
var figure:FigureStats?
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = figure?.name
numberLabel.text = figure?.number
weaponLabel.text = figure?.weapon
descLabel.text = figure?.desc
yearLabel.text = figure?.year
}
}
Try using this property. I hope it helps you.
class YourClass: UIViewController {
var currentFigure: FigureStats!
func numberOfSections(in tableView: UITableView) -> Int {
return figuresByLetter.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return figuresByLetter[section].key
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return figuresByLetter[section].value.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "figureCell", for: indexPath)
cell.textLabel?.text = figuresByLetter[indexPath.section].value[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentFigure = figuresByLetter[indexPath.section].value[indexPath.row]
print(currentFigure)
performSegue(withIdentifier: "showDetails", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? FigureViewController {
print(currentFigure)
destination.figure = currentFigure
}
}
class FigureViewController: UIViewController {
var figure:FigureStats?
override func viewDidLoad() {
super.viewDidLoad()
print(figure)
nameLabel.text = figure?.name
numberLabel.text = figure?.number
weaponLabel.text = figure?.weapon
descLabel.text = figure?.desc
yearLabel.text = figure?.year
}
}
I think your problem is that you don't send data to your showDetails (I don't see how you do it) so you see data which did add to storyboard but not data from your model, check it.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetails" {
let controller = (segue.destination as! UINavigationController).topViewController as! YourViewController
let row = (sender as! IndexPath).row
controller.figuresByLetter = figuresByLetter[row]
}
}
I have an issue with the UITableViewController: the table view shows up but didDeselectRowAt will be called only every second time when touching a cell. Does anyone see an issue with this code?
import UIKit
import MediaPlayer
class LibraryTableViewController: UITableViewController{
let mediaItems = MPMediaQuery.songs().items
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mediaItems!.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = mediaItems?[indexPath.row].title
return cell
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
print("table item selected")
OperationQueue.main.addOperation{
self.performSegue(withIdentifier: "showPlayer", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPlayer"{
let playerVC = segue.destination as! PlayerViewController
let indexPath = tableView.indexPathForSelectedRow!
playerVC.mediaItem = mediaItems?[indexPath.row]
}
}
}
Change didDeselectRowAt to didSelectRowAt