Swift TableView segue to new ViewController with wrong index path (penultimate selection) - ios

I have a weird problem.
I have two TableViews one for showing Projects and one for showing all Team Members. With both TableViews I have the same bug.
When a user clicks on a Project/ Team Member I want to show the Details for it.
The weird thing is, when running the app and I select a Project/ Team Member for the first time, nothing is happening. When I then select another one, it shows me the details of the previous selected one.
I hope someone can help me with that.
Also a weird thing is, the entry "Sarra Fezzani" was deleted from the Firebase Database and the app was clean build, but it still shows it several times...
Since both codes are pretty similiar I will only post the Code for the ProjetTableViewController without the other files.
//
// TeamViewController.swift
// ProLabArtv2
//
import UIKit
class TeamViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var memberTableView: UITableView!
#IBOutlet weak var addTeamMember: UIButton!
var members = [TeamMember]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
setUpElements()
UserService.members(for: User.current) { (members) in
self.members = members
self.memberTableView.reloadData()
}
}
// MARK: - Element Style
func setUpElements() {
// Mark: Style the elements
Utilities.addShadowtoButton(addTeamMember)
}
func configureTableView() {
// remove separators for empty cells
memberTableView.tableFooterView = UIView()
// remove separators from cells
memberTableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMemberDetails" {
let destVC = segue.destination as! TeamMemberDetailsViewController
destVC.member = sender as? TeamMember
}
}
}
// MARK: - UITableViewDataSource
extension TeamViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let member = members[indexPath.row]
let cell = memberTableView.cellForRow(at: indexPath)
print(members)
performSegue(withIdentifier: "toMemberDetails", sender: member)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return members.count
}
// func numberOfSections(in tableView: UITableView) -> Int {
// return members.count
// }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let member = members[indexPath.row]
let cell = memberTableView.dequeueReusableCell(withIdentifier: "TeamMemberCell") as! TeamMemberCell
cell.jobLabel.text = members[indexPath.row].memberJob
cell.nameLabel.text = members[indexPath.row].memberName
return cell
}
}
// MARK: - UITableViewDelegate
extension TeamViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
import UIKit
class TeamMemberCell: UITableViewCell {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
static let height: CGFloat = 78
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
}
}
import Foundation
import UIKit
import FirebaseDatabase.FIRDataSnapshot
class TeamMember {
// Next let's add properties to store all the additional information we need. Add the following to your post class.
var key: String?
let memberName: String
let memberJob: String
let memberLanguage: String
let memberPrice: String
let memberSpecification: String
// You'll get some compiler errors for not having any initializers or default values for certain properties. Let's go ahead and fix that:
init(memberName: String, memberJob: String, memberLanguage: String, memberPrice: String, memberSpecification: String) {
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
var dictValue: [String : Any] {
return ["memberName" : memberName,
"memberJob" : memberJob,
"memberLanguage" : memberLanguage,
"memberPrice" : memberPrice,
"memberSpecification" : memberSpecification]
}
init?(snapshot: DataSnapshot) {
guard let dict = snapshot.value as? [String : Any],
let memberName = dict["memberName"] as? String,
let memberJob = dict["memberJob"] as? String,
let memberLanguage = dict["memberLanguage"] as? String,
let memberPrice = dict["memberPrice"] as? String,
let memberSpecification = dict["memberSpecification"] as? String
else { return nil }
self.key = snapshot.key
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
}
import Foundation
import FirebaseAuth.FIRUser
import FirebaseDatabase
import FirebaseUI
import FirebaseAuth
struct UserService {
static func members(for user: User, completion: #escaping ([TeamMember]) -> Void) {
let ref = Database.database().reference().child("team").child(user.uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let snapshot = snapshot.children.allObjects as? [DataSnapshot] else {
return completion([])
}
let members = snapshot.reversed().compactMap(TeamMember.init)
completion(members)
})
}
}
//
// TeamMemberDetailsViewController.swift
// ProLabArtv2
//
// Created by Manu on 09.06.20.
// Copyright © 2020 Manuel Knott. All rights reserved.
//
import UIKit
import FirebaseDatabase
import FirebaseAuth
import FirebaseStorage
class TeamMemberDetailsViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
#IBOutlet weak var specificationLabel: UILabel!
#IBOutlet weak var languageLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var newScoreButton: UIButton!
#IBOutlet weak var projectsPartButton: UIButton!
var member: TeamMember?
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
func setUI() {
nameLabel.text = member?.memberName
jobLabel.text = member?.memberJob
specificationLabel.text = member?.memberSpecification
languageLabel.text = member?.memberLanguage
priceLabel.text = member?.memberPrice
// scoreLabel.text = member?.
}
}
And that's the one for the ProjectViewController, where I am using a switch statement...
// HomeViewController.swift
// ProLabArtv2
//
//
import UIKit
import Kingfisher
import Foundation
import FirebaseStorage
import FirebaseDatabase
class HomeViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var addProject: UIButton!
var posts = [Post]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
UserService.posts(for: User.current) { (posts) in
self.posts = posts
self.tableView.reloadData()
}
Utilities.addShadowtoButton(addProject)
}
func configureTableView() {
// remove separators for empty cells
tableView.tableFooterView = UIView()
// remove separators from cells
tableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails" {
let destVC = segue.destination as! ShowProjectDetailsViewController
destVC.post = sender as? Post
}
}
}
// MARK: - UITableViewDataSource
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func numberOfSections(in tableView: UITableView) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.section]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostImageCell") as! PostImageCell
let imageURL = URL(string: post.imageURL)
cell.postImageView.kf.setImage(with: imageURL)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostSubCell") as! PostSubCell
cell.projectName.text = post.projectTitle
return cell
default:
fatalError("Error: unexpected indexPath.")
}
}
}
// MARK: - UITableViewDelegate
extension HomeViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
let post = posts[indexPath.section]
return post.imageHeight
case 1:
return PostSubCell.height
default:
fatalError()
}
}
}
Hopefully someone can help me :)

This is one of those errors we've all made at some point, usually by not reading the autocomplete carefully.
Your code is
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
You've used the didDeselectRowAt rathert than didSelectRowAt method. Which means that it runs it when that row loses focus (which will be when you click on another row).
You need
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...

You are using the wrong delegate method. Perform the segue on selecting rather than deselecting a cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}

Related

How to pass data with delegate from footer cell to view controller?

Ive been stuck trying to pass data from the FoodEatenController(FEC) Footer to the TotalCaloriesController. The code that I have now it shows NOTHING in the calorieLbl of the TotalCalorieController(TCC).
The delegate that ive been using to pass the data from the FEC to the TCC does not pass the text/string data that is in the FoodFooter calorieTotallbl to the TEC calorieLbl
the data that populates the cells of the FEC is retrieved from Cloud Firestore and passed in from anotherView Controller (FoodPickerController)
import UIKit
class FoodEatenController: UIViewController{
var selectedFood: FoodList! // allows data to be passed into the VC
// allows data to be sepearted into sections
var foodItems: [FoodItem] = []
var groupedFoodItems: [String: [FoodItem]] = [:]
var dateSectionTitle: [String] = []
#IBOutlet weak var tableView: UITableView!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TotalCalorieController {
}
}
}
extension FoodEatenController: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return dateSectionTitle.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let date = dateSectionTitle[section]
return groupedFoodItems[date]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let foodCell = tableView.dequeueReusableCell(withIdentifier: "FoodCell") as! FoodCell
let date = dateSectionTitle[indexPath.section]
let foodItemsToDisplay = groupedFoodItems[date]![indexPath.row]
foodCell.configure(withCartItems: fooditemsToDisplay.foodList)
return foodCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let foodHeader = tableView.dequeueReusableCell(withIdentifier: "FoodHeader") as! FoodHeader
let headerTitle = dateSectionTitle[section]
foodHeader.dateLbl.text = "Date: \(headerTitle)"
return foodHeader
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let foodFooter = tableView.dequeueReusableCell(withIdentifier: "FoodFooter") as! FoodFooter
let date = dateSectionTitle[section]
let arrAllItems = groupedFoodItems[date]!
var total: Float = 0
for item in arrAllItems {
let eaten = item.productList
let selectedMeal = item.foodList.selectedOption
if selectedMeal == 1 {
total = total + (Float(eaten!.calorie))
}
}
foodFooter.calorieTotal.text = String(subtotal!)
foodFooter.delegate = self
return foodFooter
}
}
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
popUp.calorieLbl.text = info
}
}
import UIKit
protocol EatenFoodDelegate: class {
func onTouchCaloireInfo(info: String)
}
class FoodFooter: UITableViewCell {
weak var delegate: EatenFoodDelegate? = nil
#IBOutlet weak var calorieTotal: UILabel!
#IBOutlet weak var totalInfoBtn: UIButton!
#IBAction func totalOnClicked(_ sender: AnyObject) {
self.delegate?. onTouchCaloireInfo(info: calorieTotal.text!)
}
}
class TotalCalorieController: UIViewController, EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
calorieLbl.text = info
}
#IBOutlet weak var calorieLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func returnButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
print("Close Taxes and Fees")
}
}
Add the following line at the end of the func onTouchCaloireInfo(info:)
self.present(popUp, animated: true, completion: nil)
If you would like to be sure that the function onTouchCaloireInfo(info:) gets called, just add the following line:
debugPrint("onTouchCaloireInfo")
And check, if it prints the given string in the console of the Xcode
extension FoodEatenController: EatenFoodDelegate {
func onTouchCaloireInfo(info: String) {
debugPrint("onTouchCaloireInfo")
let popUp = self.storyboard?.instantiateViewController(withIdentifier: "AdditionalCostsVC") as! TotalCalorieController
self.present(popUp, animated: true) {
popUp.calorieLbl.text = info
}
}
}

How to pass data on button clicked in cell to another tableview?

First: How would I be able to pass data from the ItemVC Cell to the CartVC on button Clicked (Add To Cart Button(ATC)) in the selected cell, since I am no trying to use didSelectRowAt to pass the data to the CartVC. but the ATC btn to pass the cells data to the CartVC
my Segue from the ItemVC to the CartVC is in the BarButtonItem(cartBtn) so I dont want to jump to the CartVc when pressing the ATC button but only pass selected items data to CartVC when the ATC is pressed
Second how would I be able to pass the increment/decrement value in lblQty to to the CartVC when the ATC is pressed as well to be able to present a more accurate Subtotal
import UIKit
import SDWebImage
import Firebase
class ItemCell: UITableViewCell {
weak var items: Items!
#IBOutlet weak var name: UILabel!
#IBOutlet weak var category: UILabel!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var weight: UILabel!
#IBOutlet weak var price: UILabel!
#IBOutlet weak var lblQty: UILabel!
#IBOutlet weak var addToCart: RoundButton!
#IBOutlet weak var plusBtn: RoundButton!
#IBOutlet weak var minusBtn: RoundButton!
func configure(withItems : Items) {
name.text = product.name
category.text = items.category
image.sd_setImage(with: URL(string: items.image))
price.text = items.price
weight.text = items.weight
}
}
import UIKit
import Firebase
import FirebaseFirestore
class ItemViewController: UITableViewController {
#IBOutlet weak var cartBtn: BarButtonItem!!
#IBOutlet weak var tableView: UITableView!
var itemSetup: [Items] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
fetchItems { (items) in
self.itemSetup = items.sorted
self.tableView.reloadData()
}
}
func fetchItems(_ completion: #escaping ([Items]) -> Void) {
// -** FireStore Code **-
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as? CartViewController {
vc.items = self.itemSetup
}
}
#objc func plusItem(_ sender: UIButton) {
// -** increase Qty Code **-
}
//Function to decrement item count
#objc func minusItem(_ sender: UIButton) {
// -** decrease Qty Code **-
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell") as? ItemCell else { return UITableViewCell() }
cell.configure(withItem: itemSetup[indexPath.row])
cell.lblQty.text = "\(self.imageSetup[indexPath.row].count)"
cell.plusBtn.tag = indexPath.row
cell.plusBtn.addTarget(self, action: #selector(self.plusItem(_:)), for: .touchUpInside)
cell.minusBtn.tag = indexPath.row
cell.minusBtn.addTarget(self, action: #selector(self.minusItem(_:)), for: .touchUpInside)
return cell
}
}
class CartViewController: UIViewController {
var items: Items!
#IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Cart.currentCart.cartItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = Cart.currentCart.CartItems[indexPath.row]
cell.qty.text = "\(cart.qty)"
cell.lblMealName.text = "\(cart.items.category): \(cart.items.name)"
cell.lblSubTotal.text = "$\(cart.items.price1 * Float(cart.qty))"
cell.imageUrl // can't figure out how to pass image
return cell
}
}
import Foundation
class CartItem {
var items: Items
var qty: Int
init(items: Items, qty: Int) {
self.items = items
self.qty = qty
}
}
class Cart {
static let currentCart = Cart()
var cartItems = [CartItem]()
}
Just create a protocol to create a delegate and assign it to your cart class when the cell is initialized
protocol ItemCellDelegate {
func itemCell(didTapButton button: UIButton)
}
Then have a delegate property in the ItemCell
class ItemCell {
weak var delegate: ItemCellDelegate?
...
// Then call the delegate method when the buttons is tapped.
func buttonTapped() {
delegate?.itemCell(didTapButton: theCellsButton)
}
}
Then make your Cart conform to the delegate
extension Cart: ItemCellDelegate {
func itemCell(didTapButton button: UIButton) {
// Do you stuff with button, or any other data you want to pass in
}
}
Then set the delegate before the cell is returned.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = Cart.currentCart.CartItems[indexPath.row]
cell.qty.text = "\(cart.qty)"
cell.lblMealName.text = "\(cart.items.category): \(cart.items.name)"
cell.lblSubTotal.text = "$\(cart.items.price1 * Float(cart.qty))"
cell.delegate = Cart.currentCart //You should rename this static var to just 'current'
return cell
}

TableView Cell actions

I have a ViewController, with a list of data from a son file. This page run perfectly. On this page are many pub's with prices. And I want to make another scene (SecondViewController). And every time, when I push a pub from the list I want to display on another scene more information about that place. That run, but when I choose a pub the program shows the information about the first pub from the list, and when I choose another he shows the previous pub, which I choose before. And sorry my english is very bad. Please help me :D
Here is my ViewController:
import UIKit
var nev: [String] = []
var cim: [String] = []
var ar: [String] = []
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var myIndex: Int?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "pubok", withExtension: "json")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["Pubok"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
nev.append(aObject["Hely neve"] as! String)
cim.append(aObject["Cím"] as! String)
ar.append(aObject["Legolcsóbb sör"] as! String)
}
}
self.tableView.reloadData()
}
catch {
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nev.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.nevLabel.text = nev[indexPath.row]
cell.arLabel.text = ar[indexPath.row] + "/0.5l"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! SecondViewController
vc.myIndex = myIndex
}
}
Here is my SecondViewController:
import UIKit
class SecondViewController: UIViewController {
myIndex: Int?
#IBOutlet weak var secondnevLabel: UILabel!
#IBOutlet weak var secondcimLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
secondnevLabel.text = nev[myIndex!]
secondcimLabel.text = cim[myIndex!]
}
}
And this is the TableViewCell:
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var nevLabel: UILabel!
#IBOutlet weak var arLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Instead of having the global variable myIndex, have a local variable in the second view controller. Use prepare(for segue:) in the first view controller to assign the selected row index to that variable.
ViewController:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
// etc
}
// Remove didSelectRowAt
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let row = (self.tableView.indexPathForSelectedRow as NSIndexPath?)?.row
let vc = segue.destination as! SecondViewController
vc.myIndex = row
}
SecondViewController:
class SecondViewController: UIViewController {
var myIndex: Int?
#IBOutlet weak var secondnevLabel: UILabel!
#IBOutlet weak var secondcimLabel: UILabel!
// etc

How can I pass one just one part of a struct?

I'm trying to pass just the image part of a struct (containing also two textFields, and another imageView I'd like to not pass).
Here is the tableViewController
import UIKit
class SentMemesTableViewController: UITableViewController {
var _tableView: UITableView!
var memeData: [Meme] = []
//calling memes from array in Delegate
let appDelegate = UIApplication.shared.delegate as! AppDelegate
var memes: [Meme] {
return appDelegate.memes
}
override func viewWillAppear(_ animated: Bool) {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.isScrollEnabled = true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MemeDetailViewController" ,
let nextScene = segue.destination as? MemeDetailViewController ,
let indexPath = tableView.indexPathForSelectedRow {
let selectedMeme = memes[indexPath.row].memedImage
nextScene.sentMemeView.image = Meme.memedImage
}
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//navigationController!.pushViewController(MemeDetailViewController, animated: true)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return memes.count
}
// Here it is! -----
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "sentMemesTableView") as! MemeTableViewCell
let meme = memes[indexPath.row]
tableViewCell.tableViewImage.image = meme.memedImage
tableViewCell.tableViewLabel.text = "\(meme.topText)...\(meme.bottomText)"
return tableViewCell
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return false
}
func deleteMemesInTableViewCell(_ index: Int) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.memes.remove(at: index)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
tableView.beginUpdates()
deleteMemesInTableViewCell(indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left)
tableView.endUpdates()
}
}
}
Here is the Meme and SentMemeView structs.
import Foundation
import UIKit
struct Meme {
let topText: String
let bottomText: String
let originalImage: UIImage
let memedImage: UIImage
}
struct SentMemeImageView {
var memedImageDetailVC: UIImageView
}
I can't find a way to call it successfully.
Here is the MemeDetailViewController. I need just for the sentMemeView to display the SentMemeImageView.
class MemeDetailViewController: UIViewController {
var meme = SentMemeImageView?.self
#IBOutlet weak var sentMemesBtn: UIBarButtonItem!
#IBOutlet weak var editBtn: UIBarButtonItem!
#IBOutlet weak var sentMemeView: UIImageView!
func displayMeme(_ meme: SentMemeImageView) {
}
#IBAction func launchMemeEditorViewController(_ sender: Any) {
_ = navigationController?.popViewController(animated: true)
}
//unwinding to the view before (the collectionView, or the tableView)
#IBAction func unwindVC(for unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) {
self.dismiss(animated: true, completion: nil)
}
}
First of all, sad to say that, your code is quite messed up:
You have with three different kinds of data sources, some are ignored, some you work with, but not in a consistent way:
data from the app delegate (deletion of data)
memeData property (display of data)
memes property (ignored)
You should really focus on where the data is stored and how to access it.
Secondly, you won't send views from one view controller to the other, but data. So rather use UIImage than UIImageView. So you'll hand in a SentMemeImage to the details controller.
I tried to clean up the code a little, but just to answer your explicit question. Please refactor it!
struct Meme {
let topText: String
let bottomText: String
let originalImage: UIImage
let memedImage: UIImage
}
struct SentMemeImage {
var memedImage: UIImage
}
class SentMemesTableViewController: UITableViewController {
var memeData: [Meme] = []
// ----8<---- snipp ----8<----
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MemeDetailViewController" ,
let nextScene = segue.destination as? MemeDetailViewController ,
let indexPath = tableView.indexPathForSelectedRow {
let selectedMeme = memeData[indexPath.row]
let sentMemeImage = SentMemeImage(memedImage: selectedMeme.memedImage)
nextScene.meme = sentMemeImage
}
}
// ----8<---- snipp ----8<----
}
class MemeDetailViewController: UIViewController {
var meme:SentMemeImage?
#IBOutlet weak var sentMemesBtn: UIBarButtonItem!
#IBOutlet weak var editBtn: UIBarButtonItem!
#IBOutlet weak var sentMemeView: UIImageView!
func displayMeme() {
self.sentMemeView.image = self.meme?.memedImage
}
}

How to pass TableViewCell value into new ViewController in Swift 3.0?

I have this JSON data
move.json
{
"status":"ok",
"movement":
[
{
"refno":"REF 1",
"dtfrom":"2017-13-12"
},
{
"refno":"REF 2",
"dtfrom":"2017-13-13"
},
{
"refno":"REF 3",
"dtfrom":"2017-13-14"
},
]
}
So far, I managed to fetch the value into TableViewCell.
But my goal is to pass the value from ViewController.swift into MoveDetails.swift so the value can be display in MoveDetails.swift
And I have these four swift files. I'm having the problem on ViewController.swift and MoveDetails.swift. I'm not sure how to pass the value into new Controller.
The code as below.
ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var move: [Move]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
let urlRequest = URLRequest(url: URL(string: "http://localhost/move.json")!)
let task = URLSession.shared.dataTask(with: urlRequest) {
(data,response,error)in
if error != nil { return }
self.move = [Move]()
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let msFromJson = json["movement"] as? [[String: AnyObject]] {
for mFromJson in msFromJson {
let ms = Move()
if let refno = mFromJson["refno"] as? String, let dtfrom = mFromJson["dtfrom"] as? String {
ms.refno = refno
ms.dtfrom = dtfrom
}
self.move?.append(ms)
}
}
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
catch let error{ print(error)}
}
task.resume()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "movementstatusCell", for: indexPath) as! MoveCell
cell.refnoLbl.text = self.move?[indexPath.item].refno
cell.dtfromLbl.text = self.move?[indexPath.item].dtfrom
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.move?.count ?? 0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "MoveDetails") as! MoveDetails
let selectedMove = self.move?[indexPath.item]
vc.refnoString = selectedMove.refno
vc.dtfromString= selectedMove.dtfrom
self.navigationController?.pushViewController(vc, animated: true)
}
}
MoveCell.swift
import UIKit
class MoveCell: UITableViewCell {
#IBOutlet weak var dtfromLbl: UILabel!
#IBOutlet weak var refnoLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Move.swift (NSObject)
import UIKit
class Move: NSObject {
var refno: String?
var dtfrom: String?
}
MoveDetails.swift
import UIKit
class MoveDetails: UIViewController {
#IBOutlet weak var refnoLbl: UILabel!
#IBOutlet weak var dtfromLbl: UILabel!
var refnoString: String!
var dtfromString: String!
override func viewDidLoad() {
super.viewDidLoad()
refnoString = refnoLbl.text
dtfromString = dtfromLbl.text
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
}
Appreciate if someone can help. Thanks.
You will just have to set the properties of your MoveDetails view controller. And as a suggestion
Instead of storing refnoString and dtfromString properties in MoveDetails, you could just store one property of type Move:
Cache MoveDetails view controller to reuse it
Implement viewDidAppear to update the MoveDetails outlets
So:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var detailsVC : MoveDetails?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (detailsVC == nil) {
detailsVC = self.storyboard?.instantiateViewController(withIdentifier: "MoveDetails") as! MoveDetails
}
detailsVC.move = self.move?[indexPath.item]
self.navigationController?.pushViewController(detailsVC , animated: true)
}
}
Then, override viewDidAppear in MoveDetails view controller and there you just fill in the values into the text label outlets.
class MoveDetails: UIViewController {
#IBOutlet weak var refnoLbl: UILabel!
#IBOutlet weak var dtfromLbl: UILabel!
var move:Move?
override func func viewDidAppear(_ animated: Bool) {
refnoLbl.text = move?.refno
dtfromLbl.text = move?.dtfrom
}
}
Syntax errors cause because I currently have no Xcode available to do the checking

Resources