显示UITableViewCell中多个图像上传的进度指示器

时间:2016-09-16 04:31:26

标签: ios objective-c uitableview

我有自定义单元格的UITableView。我想显示多个图片上传的进度指示器。

我已经尝试过UITableView的 reloadRowAtIndexPath 方法,但这还不够解决,因为单元格一直闪烁,看起来很奇怪。

我找到的另一个解决方案是将我的进度指示器视图的参考存储在全局变量中的UITableViewCell中,然后在UITableView数据源方法之外修改它,但在这个解决方案中我遇到了一个问题,即我必须跟踪UITableViewCell的多个进度指示器视图对象,这很难,因为UITableView数据源是二维NSMutableArray(在数组内部的短数组中)所以我没有唯一的IndexPath.row,因为有多个部分。那么如何管理进度指示器视图的对象呢?

还有更好的解决方案来完成这类工作吗?

5 个答案:

答案 0 :(得分:1)

好的,所以这是我在其中一个项目中使用的,当时我找不到任何其他内容。

Swift 3

创建NSObject的子类(因为URLSession的子类不允许您将配置和其他参数设置为唯一指定的初始化器,其中包含init()),其中包含启动上载过程的单元的信息在IndexPath和URLSession对象。

使用此子类在您想要上传时创建新的URLSession(我使用了URLSession的uploadTask方法)。

创建uploadTask并开始上传。

您还必须制作自己的协议方法,这些方法由URLSession的常规协议方法调用,以将您的自定义子类而不是URLSession对象发送到您想要的委托。

然后在该委托中,您可以检查存储在您从上一步骤获得的自定义子类中的indexPath的信息,并更新相应的单元格。

通过使用Notifications我可以实现同样的目标。

以下是我写的示例应用程序的屏幕截图:

enter image description here

public class TestURLSession:NSObject, URLSessionTaskDelegate {

    var cellIndexPath:IndexPath!
    var urlSession:URLSession!
    var urlSessionUploadTask:URLSessionUploadTask!
    var testUrlSessionDelegate:TestURLSessionTaskDelegate!

    init(configuration: URLSessionConfiguration, delegate: TestURLSessionTaskDelegate?, delegateQueue queue: OperationQueue?, indexPath:IndexPath){
        super.init()
        self.urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: queue)
        self.cellIndexPath = indexPath
        self.testUrlSessionDelegate = delegate
    }

    func uploadTask(with request: URLRequest, from bodyData: Data) -> URLSessionUploadTask{
        let uploadTask = self.urlSession.uploadTask(with: request, from: bodyData)
        self.urlSessionUploadTask = uploadTask
        return uploadTask
    }


    public func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64){
        self.testUrlSessionDelegate.urlSession(self, task: self.urlSessionUploadTask, didSendBodyData: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend)
    }

}

protocol TestURLSessionTaskDelegate : URLSessionDelegate {

    func urlSession(_ session: TestURLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)

}

欢迎编辑。

答案 1 :(得分:0)

这里我应用的解决方案可能对想要我想要的相同实现的人有所帮助,而不使用第三方库或类。

我使用UIView和一些动画创建了一个自定义CALayer和设计循环进度指示器。这不是什么大问题。但对我来说困难的是我想在几个单元格中指示这个进度指示器,这表示多个图像的百分比进度。

所以我创建了一个具有

等属性的自定义类
@property (nonatomic,retain) NSIndexPath              *indexPath;
@property (nonatomic,strong) NSURLSessionTask         *uploadtask;

然后我维护一个NSMutableArray,其中包含我的自定义类对象,其中包含当前上载图像的每个uploadTask的值和包含indexPath的合并字符串。现在我跟踪了我的所有上传图片,所以每当我收到来自NSURLSession的委托方法的回复时,我在自定义进度指示器UIView中使用indexPath值更改上传的百分比。

答案 2 :(得分:0)

我有类似的事情要做,我想在哪里下载文件并显示进度条。我的想法是创建一个自定义对象,跟踪特定的下载,所有单元格将在内部监听此对象的更改。每个单元格都有自己的对象,由任务标识符唯一标识。我在Swift 3中编写了一个示例代码,可在以下链接中找到(骨架代码也已添加)

FileDownloader

class DownLoadData: NSObject {
    var fileTitle: String = ""
    var downloadSource: String = ""
    var downloadTask: URLSessionDownloadTask?
    var taskResumeData: Data?
    var downloadProgress: Float = 0.0
    var isDownloading: Bool = false
    var isDownloadComplete: Bool = false
    var taskIdentifier: Int = 0
    var groupDownloadON:Bool = false
    var groupStopDownloadON:Bool = false

    init(with title:String, and source:String){
        self.fileTitle = title
        self.downloadSource = source
        super.init()

    }

    func startDownload(completion:@escaping (Result<Bool, Error>)->Void,progressHandler:@escaping (Float)->Void ){

    }
    func resumeDownload(completion:@escaping (Result<Bool, Error>)->Void,progressHandler:@escaping (Float)->Void ){


    }

    func pauseDownload(){

    }

    func stopDownload(){

        if self.isDownloading{

        }
    }
    func cleanUpHandlers(){

        // remove the completion handlers from the network manager as resume is taken as a new task.

    }
    func handleDownloadSuccess(){

    }
    func handleDownloadError(){


    }
}

答案 3 :(得分:-1)

使用URLSessionTaskDelegate方法并进行必要的计算:

func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)

答案 4 :(得分:-1)

以下是一种解决方案,已针对单个文件上传进行了测试。但是您可以对其进行修改以支持多个文件上传。确保根据需要添加必要的IBOutlets和IBAction。该图像已添加到“ Assets.xcassets”中。

我的UI如下所示:

enter image description here

下面是ViewController的代码。

import UIKit

class UploadProgressViewController: UIViewController, URLSessionTaskDelegate {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var progressView: UIProgressView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    progressView.progress = 0.0
}

@IBAction func didTapOnStartUploadButton(_ sender: Any) {
    startDownload()
}

func startDownload () {
    // 1. Prepare data to download
    var data = Data()
    if let image = UIImage(named: "swift.jpg") {
        data = image.pngData()!
    }
    // 2. Creation of request
    var request = URLRequest(url: NSURL(string: "http://127.0.0.1:8000/swift.png")! as URL)
    request.httpMethod = "POST"
    request.setValue("Keep-Alive", forHTTPHeaderField: "Connection")
    // 3. Configuring the Session
    let configuration = URLSessionConfiguration.default
    let mainqueue = OperationQueue.main
    // 4. Start the upload task
    let session = URLSession(configuration: configuration, delegate:self, delegateQueue: mainqueue)
    let dataTask = session.uploadTask(with: request, from: data)
    dataTask.resume()
}

// URLSessionTaskDelegate Handling

func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
    let uploadProgress: Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
    print("session \(session) uploaded \(uploadProgress * 100)%.")
    progressView.progress = uploadProgress
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    print(error.debugDescription)
}