Get IndexPath from a UITableViewCell in a multiple sections UITableView to respond a Notification

251 Views Asked by At

I have a tableView with multiple sections and i want to show in a cell (via notification) the progress of a download that is being handle by Alamofire.

Right now, i already have the notification post working and passing as info, an episode object, like this:

let info = ["episode": episode, "progress": progress.fractionCompleted] as [String : Any]
NotificationCenter.default.post(name: .downloadProgress, object: nil, userInfo: info)

Each of cells have an episode object. So i want to find the IndexPath of a cell that have an episode object that matches with the episode object that is being passed from a notification.

I can't figure out how can loop through my cells to find which one have that episode and get it's indexPath so i can respond to the notification properly.

I tried to get the index of the array that is being dataSource but as the tableView has multiple sections, this is not working.

Can someone help me? Thanks

My TableViewController:

//
//  EpisodesViewController.swift
//  Podee
//
//  Created by Vinícius Barcelos on 21/07/18.
//  Copyright © 2018 Vinícius Barcelos. All rights reserved.
//

import UIKit
import RealmSwift
import Kingfisher

class EpisodesTableViewController: UITableViewController {

    //MARK:- Variables
    var episodes: Results<Episode> = RealmService.shared.read(object: Episode.self).sorted(byKeyPath: "pubDate", ascending: true)
    let episodesCellId = "episodesCellId"
    var notificationToken: NotificationToken?

    var episodesDictionary = Dictionary<Date, [Episode]>()
    var dateDays = [Date]()

    //MARK:- Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
        setupObservers()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tableView.reloadData()
    }

    deinit {
        self.notificationToken?.invalidate()
        //NotificationCenter.default.removeObserver(self, name: NSNotification.Name.downloadProgress, object: nil)
    }


    //MARK:- Setup
    fileprivate func setupObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleDownloadProgressNotification(notification:)), name: .downloadProgress, object: nil)
        }
    }

    @objc func handleDownloadProgressNotification(notification:Notification) {
        ////////
    }


    //MARK:- Tableview methods
    override func numberOfSections(in tableView: UITableView) -> Int {
        return episodesDictionary.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let key = dateDays[section]
        guard let datesValues = episodesDictionary[key] else {
            return 0
        }
        return datesValues.count
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd MMMM"
        return dateFormatter.string(from: dateDays[section])
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: episodesCellId, for: indexPath) as! EpisodesTableViewCell

        let key = dateDays[indexPath.section]

        if let podcastValues = episodesDictionary[key] {
            cell.delegate = self
            cell.progressBar.isHidden = true
            cell.episode = podcastValues[indexPath.row]
        }
        return cell
    }

}

Download code:

// Start download
        Alamofire.request(episode.streamURL).downloadProgress { (progress) in
        // Send a notification about the download progress
        let info = ["episode": episode, "progress": progress.fractionCompleted] as [String : Any]
        NotificationCenter.default.post(name: .downloadProgress, object: nil, userInfo: info)
        //print(progress)
        // Check data
    }.responseData { (responseData) in ......
1

There are 1 best solutions below

1
On BEST ANSWER

Modify your function of download and add the following parameters

 func downloadFile(url: String,date: Date, index: Int){
        let utilityQueue = DispatchQueue.global(qos: .utility)
        Alamofire.download(url)
            .downloadProgress(queue: utilityQueue) { progress in
                let info: [String: AnyHashable] = ["date": date,
                             "index" : index,
                             "progress": progress.fractionCompleted
                ]
                NotificationCenter.default.post(name: .downloadProgress, object: nil, userInfo: info)
            }
            .responseData { response in
              ......  
        }
    }

In your viewcontroller, replace the function with following code:

@objc func handleDownloadProgressNotification(notification:Notification) {
        var dateDays = [Date]()
        guard let info = notification.userInfo,
        let date = info["date"] as? Date,
        let index = info["index"] as? Int,
        let progress = info["progress"] as? Double,
        let section = dateDays.index(where: {$0 == date})
        else {return}

        let indexPath = IndexPath(item: index, section: section)

    }

In the download function we are passing the date and index of the row from where you started the download and you are returning it back with notification. you can also send section and row index to download function. it's mainly upto you how you want to track the row. you could've also set delegate instead of notification to track the download progress