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