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
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
}
I am a beginner in swift and I really want to fix this problem. What I am trying is to pass data from tableview to another but when I run the code, it only show me a blank tableview. Here is my code in source tableviewcontroller:
import UIKit
class C1TableViewController: UITableViewController {
var categorisePagePOneName = ["CLOTHING", "SHOES", "ACCESSORIES", "THEME"]
var selectedIndex = Int()
override func viewDidLoad() {
super.viewDidLoad()
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categorisePagePOneName.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdt = "Conecell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdt, for: indexPath) as! C1TableViewCell
cell.textLabel?.text = categorisePagePOneName[indexPath.row]
// Configure the cell...
return cell
}
func laodForNextPage(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath, segue: UIStoryboardSegue, sender: AnyObject?) {
performSegue(withIdentifier: "connect2", sender: self)
self.selectedIndex = indexPath.row
if segue.identifier == "connect2" {
let vc = segue.destination as! C2TableViewController
vc.firstRow = categorisePagePOneName[self.selectedIndex]
}
}
}
Then here is my code in another tableViewController:
import UIKit
class C2TableViewController: UITableViewController {
var firstRow: String!
var secondArray: [String] = []
var clothingCat = ["ALL CLOTHING", "THEME", "JACKET", "T-SHIRT", "SHIRT", "SWEATSHIRT", "HOODIES", "PANTS", "JEANS", "SHORTS", "KNITWEAR", "VESTS"]
var shoesCat = ["ALL SHOES", "THEME", "BOOTS", "SANDALS", "SNEAKERS"]
var asscessoriesCat = ["ALL ASSCESSORIES", "THEME", "HAT","BAGS", "JEWELLERY", "EYEWEAR", "WATCHES", "WALLETS", "SOCKS", "UNDERWEAR"]
var themeCat = ["VINTAGE", "KOREA","JAPAN", "SPORTY"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in 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 secondArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "C2", for: indexPath) as! C2TableViewCell
// Configure the cell...
switch firstRow {
case "CLOTHING":
secondArray = clothingCat
case "SHOES":
secondArray = shoesCat
case "ASSCESSORIES":
secondArray = asscessoriesCat
case "THEME":
secondArray = themeCat
default:
break
}
cell.textLabel?.text = secondArray[indexPath.row]
return cell
}
}
I am not sure if I am using switch in this case correctly
Replace (the custom method laodForNextPage is useless anyway)
func laodForNextPage(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath, segue: UIStoryboardSegue, sender: AnyObject?) {
performSegue(withIdentifier: "connect2", sender: self)
self.selectedIndex = indexPath.row
if segue.identifier == "connect2" {
let vc = segue.destination as! C2TableViewController
vc.firstRow = categorisePagePOneName[self.selectedIndex]
}
}
with
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
performSegue(withIdentifier: "connect2", sender: indexPath)
}
and implement
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "connect2" {
let indexPath = sender as! IndexPath
let vc = segue.destination as! C2TableViewController
vc.firstRow = categorisePagePOneName[indexPath.row]
}
}
And you can delete selectedIndex
You need to add this function while the sender is the indexPath
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
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 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 :)
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]
}
}