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

江枫思渺然 提交于 2021-02-05 08:28:07

问题


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 :)


回答1:


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) {
        ...




回答2:


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)
}


来源:https://stackoverflow.com/questions/62287068/swift-tableview-segue-to-new-viewcontroller-with-wrong-index-path-penultimate-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!