дубликаты данных, отображаемые в UITableView после увольнения UIViewController

#ios #swift #uitableview #uicollectionview #delegates

Вопрос:

Проблемы : UITableView заполняет дубликаты данных даже после удаления массива, когда он закрывается

Ожидаемый результат:

UITableView заполняет данные на основе итенарных элементов в массиве

Фактический объем производства:

UITableView заполняет правильный вывод суммы, когда пользователь выбирает первое местоположение в DiscoverVC, но когда пользователь выбирает другое местоположение, в tableview добавляются дополнительные данные, которые пользователь выбрал ранее.

Краткие сведения:

У меня есть 3VC в моем проекте, первый vc (DiscoverVC), вызовет api для заполнения данных в UICollectionView, я реализую делегат UICollectionView для перехода на другой экран с помощью segue, в разделе подготовка segue я передаю данные из первого vc во второй vc (ItenaryVC), во втором vc у меня есть 2 представления внутри него. Один обычный vc, а второй-плавающая панель (ItenaryFP). Когда загрузится второй vc, он выполнит вызовы API на основе объекта местоположения, который был передан из первого vc, и передаст данные третьему vc, который является плавающей панелью (ItenaryFP), через делегат в ItenaryVC.

PS; Я использую пользовательскую ячейку для просмотра таблицы и уже пытался удалить массив из viewWillAppear и viewDidDissapear, но он все еще не работает

GIF о том, как возникают проблемы

Вот краткое изложение моего кода

DiscoverVC.swift

   class DiscoverVC : UIViewController {
    //MARK:- IBOutlets
    @IBOutlet weak var collectionView: UICollectionView!
    
    private var locationResult = [Location]()
    private var selectedAtRow : Int!
    
    //MARK:- Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        renderView()
        getLocations()
    }
    
    private func renderView() {
        collectionView.register(UINib(nibName: R.nib.discoverCell.name, bundle: nil), forCellWithReuseIdentifier: R.reuseIdentifier.discoverCell.identifier)
        collectionView.delegate = self
        collectionView.dataSource = self
    }
    
    private func getLocations(location : String = "locations") {
        
        NetworkManager.shared.getLocations(for: location) {  [weak self] location in
            
            switch location {
            
            case .success(let locations):
                self?.updateDiscoverUI(with: locations)
                
            case .failure(let error):
                print(error.rawValue)
            }
        }
    }
    
    private func updateDiscoverUI(with locations : [Location]) {
        
        DispatchQueue.main.async { [weak self] in
            self?.locationResult.append(contentsOf: locations)
            self?.collectionView.reloadData()
        }
    }
}

//MARK:- Delegate
extension DiscoverVC : UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        
        selectedAtRow = indexPath.row
        self.performSegue(withIdentifier: R.segue.discoverVC.goToDetails, sender: self)
        
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        guard let destinationVC = segue.destination as? ItenaryVC else { return}
        // Passing location object to ItenaryVC
        destinationVC.locationName = locationResult[selectedAtRow]
        destinationVC.imageURL = locationResult[selectedAtRow].image
      
        // Remove tab bar when push to other vc
        destinationVC.hidesBottomBarWhenPushed = true
        
    }
}
 

ItenaryVC.swift

    protocol ItenaryVCDelegate : AnyObject {
        func didSendItenaryData(_ itenaryVC : ItenaryVC, with itenary : [[Days]])
        func didSendLocationData(_ itenaryVC : ItenaryVC, with location : Location) 
    }
    
    class ItenaryVC: UIViewController {
        
        @IBOutlet weak var backgroundImage: UIImageView!
        
        var fpc : FloatingPanelController!
        var imageURL : URL?
        var locationName: Location?
    
        weak var delegate : ItenaryVCDelegate?
        
        //MARK:- Life Cycle
        override func viewDidLoad() {
            super.viewDidLoad()
            setupCard()
            setupView()
        }
        
        override func viewWillAppear(_ animated: Bool) {
            // Call API for data
            getItenaries(at: locationName!.itenaryName)
            print("ItenaryVC Appear")
        }
        override func viewWillDisappear(_ animated: Bool) {
            locationName = nil
        }
       
        
    }
    
    //MARK:- Network Request
    extension ItenaryVC {
        
        func getItenaries(at itenaries : String = "Melaka"){
            print("itenaries  : (itenaries)")
            NetworkManager.shared.getItenaries(for: itenaries) { [weak self] itenary in
                switch itenary {
                
                case .success(let itenary):
                    // print(itenary)
                    DispatchQueue.main.async {
                        // Passing data to itenaryFP
                        self?.delegate?.didSendItenaryData(self! , with: itenary)
                    }
                    
                    print(itenaries.count)
                case .failure(let error):
                    print(error.rawValue)
                }
            }
        }
    }
    
    //MARK:- Private methods
    extension ItenaryVC {
        
        private func setupView() {
         
            
            backgroundImage.downloaded(from: imageURL!)
            backgroundImage.contentMode = .scaleAspectFill
            // Passing data to itenaryFP
            delegate?.didSendLocationData(self, with: locationName!)
        }
        
        private func setupCard() {
            guard let itenaryFlotingPanelVC = storyboard?.instantiateViewController(identifier: "itenaryPanel") as? ItenaryFP else { return}
            // Initliase delegate to Floating Panel, create strong reference to Panel
            self.delegate = itenaryFlotingPanelVC
          
            fpc = FloatingPanelController()
            fpc.set(contentViewController: itenaryFlotingPanelVC)
            fpc.addPanel(toParent: self)
            fpc.delegate = self
            fpc.layout = self
            
        }
    }
 

Это очень быстро.

    class ItenaryFP: UIViewController{
    
    
    var itenaries = [[Days]]()
    var location : Location?
    
    //MARK:- : Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        print("ItrenaryFP viewDidLoad, itenaries : (itenaries.count), location : (location)")
        renderView()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        itenaries.removeAll()
        itenaryTableView.reloadData()

    }
    
    override func viewWillDisappear(_ animated: Bool) {
      
        DispatchQueue.main.async {
         
            self.itenaries.removeAll()
            print("ItenarFP dissapear, itenaries :(self.itenaries.count), location : (self.location)")
            self.location = nil
            self.itenaryTableView.reloadData()
        }

    }
    
   private func renderView() {
        itenaryTableView.register(UINib(nibName: R.nib.itenaryCell.name, bundle: nil), forCellReuseIdentifier: R.nib.itenaryCell.identifier)
        
        itenaryTableView.dataSource = self
        itenaryTableView.delegate = self
        
        locDescHC.constant = locDesc.contentSize.height
    }
}

//MARK:- Data source
extension ItenaryFP : UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        
        return itenaries.count
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return itenaries[section].count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


        let cell : ItenaryCell = itenaryTableView.dequeueReusableCell(withIdentifier: R.nib.itenaryCell.identifier, for: indexPath) as! ItenaryCell
     
        let listOfItenaries = itenaries[indexPath.section][indexPath.row]
        
        cell.cellContent(for: listOfItenaries)
    
        return cell
    }
}



//MARK:- ItenaryVC Delegate
extension ItenaryFP : ItenaryVCDelegate {
    
    
    func didSendLocationData(_ itenaryVC: ItenaryVC, with location: Location) {

        DispatchQueue.main.async {
            self.locationLabel.text = location.locationName
            self.locDesc.text = location.description
            self.sloganLabel.text = location.slogan
        }
    }
    
    
    func didSendItenaryData(_ itenaryVC: ItenaryVC, with itenary: [[Days]]) {
        
        
        DispatchQueue.main.async {
            self.itenaries.append(contentsOf: itenary)
            self.itenaryTableView.reloadData()
            print("itenary (self.itenaries.count)")
        }
    }
}
 

Комментарии:

1. Вам нужно установить некоторые точки останова или добавить несколько print(...) операторов, где, по вашему мнению , очищается ваш массив.

Ответ №1:

Воспользуйся:

 self.itenaries = itenary 
 

Вместо:

 self.itenaries.append(contentsOf: itenary)