我使用didSelectRowAt indexPath:
中的代码在单击单击时启动下载文件,并使用cellForRowAt indexPath:
中的代码显示正在下载文件的进度。
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (mainArray[buttonIndex] as AnyObject).count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "cell", indexPath.row), for: indexPath)
let circularProgressViewForCell = FFCircularProgressView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(24), height: CGFloat(24)))
cell.accessoryView = circularProgressViewForCell
circularProgressViewForCell.isHidden = true
DownloadManager.shared.onProgress = { (progress) in
circularProgressViewForCell.isHidden = false
OperationQueue.main.addOperation {
circularProgressViewForCell.progress = CGFloat(progress)
if (cell.accessoryView as! FFCircularProgressView?)?.progress == 1.0 {
print("FFCircularProgressView")
(cell.accessoryView as! FFCircularProgressView?)?.circularState = .completed
}
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let url = URL(string: "link")!
let downloadTaskLocal = DownloadManager.shared.activate().downloadTask(with: url)
downloadTaskLocal.resume()
}
}
我在DownloadManager
创建了URLSession:
import Foundation
class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {
static var shared = DownloadManager()
typealias ProgressHandler = (Float) -> ()
var onProgress : ProgressHandler? {
didSet {
if onProgress != nil {
let _ = activate()
}
}
}
override private init() {
super.init()
}
func activate() -> URLSession {
let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")
return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
}
private func calculateProgress(session : URLSession, completionHandler : @escaping (Float) -> ()) {
session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
let progress = downloads.map({ (task) -> Float in
if task.countOfBytesExpectedToReceive > 0 {
return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
} else {
return 0.0
}
})
completionHandler(progress.reduce(0.0, +))
}
}
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL){
let fileName = downloadTask.originalRequest?.url?.lastPathComponent
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(id)"))
do {
try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil)
destinationURLForFile.appendPathComponent(String(describing: fileName!))
try fileManager.moveItem(at: location, to: destinationURLForFile)
}catch(let error){
print(error)
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if totalBytesExpectedToWrite > 0 {
if let onProgress = onProgress {
calculateProgress(session: session, completionHandler: onProgress)
}
let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
debugPrint("Progress \(downloadTask) \(progress)")
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
debugPrint("Task completed: \(task), error: \(error)")
}
}
我想点击单元格,启动文件下载并显示所选单元格中下载文件的进度。我可以在didSelectRowAt indexPath:
中创建我的progressView,但它不是最佳解决方案,因为用户可能会移动我的应用中的上一个或下一个控制器,或者可能会在下载处于活动状态时隐藏应用。当用户在TableViewController中返回时,我更新了cellForRowAt indexPath:
。
问题:当我开始下载文件时,我的进度不会显示在选定的行中。进度显示在屏幕外的行中。当我滚动tableView时,我看到所有单元格中的进度都在变化。如何解决它并显示所选单元格的进度?
UPD
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var item = self.items[indexPath.row]
if item.downloadStatus == .inProgress || item.downloadStatus == .completed {
print("video already downloaded")
}
else {
let url = URL(string: "link\(indexPath.row)")!
let int = self.tableId + indexPath.row // table0 = 1000, table1 = 2000 and etc.
DownloadManager.shared.identifier = int
let downloadTaskLocal = DownloadManager.shared.activate().downloadTask(with: url)
downloadTaskLocal.resume()
DownloadManager.shared.onProgress = { (row, progress) in
var row = row
row = row - self.tableId
DispatchQueue.main.async {
let indexpath = IndexPath.init(row: row, section: 0)
let cell = self.tableView.cellForRow(at: indexpath)
print("downloading for cell \(String(describing: cell?.tag))")
if progress <= 1.0 {
let progressRing = cell?.accessoryView as! FFCircularProgressView
progressRing.progress = CGFloat(progress)
if progress == 1.0 {
item.downloadStatus = .completed
cell?.textLabel?.text = "Download Complete"
}
else {
cell?.textLabel?.text = "Download In Progress"
}
}
}
}
UPD 1
import UIKit
import StoreKit
enum DownloadStatus {
case none
case inProgress
case completed
case failed
}
struct item {
var title : String!
let link = ""
var downloadStatus : DownloadStatus = .none
init(title: String) {
self.title = title
}
}
var id = ""
class MasterViewController: UITableViewController {
var mainArray:[[Any]] = []
var index = 0
var buttonIndex = 0
var objects = [Any]()
var items = [item]()
var tableId = 0
override func viewDidLoad() {
super.viewDidLoad()
items.append(item(title: "Video 1"))
items.append(item(title: "Video 2"))
items.append(item(title: "Video 3"))
items.append(item(title: "Video 4"))
items.append(item(title: "Video 5"))
items.append(item(title: "Video 6"))
items.append(item(title: "Video 7"))
items.append(item(title: "Video 8"))
items.append(item(title: "Video 9"))
items.append(item(title: "Video 10"))
items.append(item(title: "Video 11"))
items.append(item(title: "Video 12"))
if buttonIndex == 0 {
id = "id0"
tableId = 1000
}
else if buttonIndex == 1 {
id = "id1"
tableId = 2000
}
mainArray = [array0,array1,array2,array3,array4,array5,array6]
NotificationCenter.default.addObserver(self, selector: #selector(self.onApplicationDidBecomeActiveNotification), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
}
func onApplicationDidBecomeActiveNotification(notification:Notification) {
self.tableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.reloadData()
}
override func viewDidAppear(_ animated: Bool) {
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (mainArray[buttonIndex] as AnyObject).count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "cell", indexPath.row), for: indexPath)
let item = items[indexPath.row]
print(item.downloadStatus)
if item.downloadStatus != .completed {
let progressRing = FFCircularProgressView(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
cell.tag = indexPath.row
cell.accessoryType = UITableViewCellAccessoryType.none
cell.accessoryView = progressRing
}
else {
cell.accessoryView = nil
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var item = self.items[indexPath.row]
if item.downloadStatus == .inProgress || item.downloadStatus == .completed {
print("video already downloaded")
}
else {
let url = URL(string: "link\(indexPath.row + 1).mp3")!
let int = self.tableId + indexPath.row
let downloadManager = DownloadManager()
downloadManager.identifier = int
downloadManager.folderPath = id
let downloadTaskLocal = downloadManager.activate().downloadTask(with: url)
downloadTaskLocal.resume()
downloadManager.onProgress = { (row, progress) in
var row = row
row = row - self.tableId
DispatchQueue.main.async {
let indexpath = IndexPath.init(row: row, section: 0)
let cell = self.tableView.cellForRow(at: indexpath)
print("downloading for cell \(String(describing: cell?.tag))")
if progress <= 1.0 {
let progressRing = FFCircularProgressView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(24), height: CGFloat(24)))
cell?.accessoryView = progressRing
progressRing.progress = CGFloat(progress)
if progress == 1.0 {
item.downloadStatus = .completed
}
}
}
}
}
FirstViewController的代码
import UIKit
import StoreKit
class TableViewController: UITableViewController {
let array = ["","","","","","",""]
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
let newBackButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
self.navigationItem.backBarButtonItem = newBackButton
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.button.tag = indexPath.row
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 165.0
}
public override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 12.0
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.destination is MasterViewController) {
if let button = sender as? UIButton {
(segue.destination as? MasterViewController)?.buttonIndex = button.tag
}
}
}
}
TableViewCell的代码
import UIKit
class TableViewCell: UITableViewCell {
@IBOutlet weak var button: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
答案 0 :(得分:2)
@Artem我在DownloadManager中添加了一个属性,作为&#39;标识符&#39; (INT)。这将保存indexpath.row值。
在ProgressHandler完成块中发回此标识符值。
附上上述更改的更新代码。
static var shared = DownloadManager()
var identifier : Int = -1
typealias ProgressHandler = (Int, Float) -> ()
var onProgress : ProgressHandler? {
didSet {
if onProgress != nil {
let _ = activate()
}
}
}
override private init() {
super.init()
}
func activate() -> URLSession {
let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")
return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
}
private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Float) -> ()) {
session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
let progress = downloads.map({ (task) -> Float in
if task.countOfBytesExpectedToReceive > 0 {
return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
} else {
return 0.0
}
})
completionHandler(self.identifier, progress.reduce(0.0, +))
}
}
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL){
let fileName = downloadTask.originalRequest?.url?.lastPathComponent
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(id)"))
do {
try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil)
destinationURLForFile.appendPathComponent(String(describing: fileName!))
try fileManager.moveItem(at: location, to: destinationURLForFile)
}catch(let error){
print(error)
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if totalBytesExpectedToWrite > 0 {
if let onProgress = onProgress {
calculateProgress(session: session, completionHandler: onProgress)
}
let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
debugPrint("Progress \(downloadTask) \(progress)")
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
debugPrint("Task completed: \(task), error: \(String(describing: error))")
}
}
在您的DownloadManager中
类DownloadManager:NSObject,URLSessionDelegate,URLSessionDownloadDelegate {
pragma integrity_check
更新的答案
我创建了一个简单的项目来演示UITableViewCell上的下载进度更新。
https://github.com/mcabasheer/table-cell-progress-bar/tree/master
希望这会有所帮助:)
答案 1 :(得分:0)
您的案例中的问题是细胞的重复使用
在tableView(: cellForRowAt:)
中,您必须管理用户从具体单元格下载而不是下载的事实
您的DownloadManager似乎不知道您要从哪个网址(单元格)下载。
例如,保留所选网址的数组。
答案 2 :(得分:0)
对于渐进式下载并向tableview显示,您必须按照以下步骤操作
步骤1 :单击单元格时,将其索引存储在数组中。 (我们将该名称命名为arrDownloads
)
第2步:在cellForRowAtIndexPath
中检查arrDownloads
是否包含当前索引路径
第3步:如果cellForRowAtIndexPath
中的当前索引位于arrDownloads
内,则将当前索引的URL传递给下载管理器。 (确保您有另一组URL来下载图像(文件))
This可能会有所帮助。
答案 3 :(得分:0)
我想,你在tableView的标题中设置你的进度。滚动桌面视图时,您可以看到进度。