[英]How to update progressview in uitableview cell by urlsession (download/upload file)
在 Objective ci 中,AFNETWORKING 在 uitableviewcell 中使用進度視圖編寫了下載/上傳(多次上傳/下載)。 並發現它可以是更新進度視圖/文件/單元格。
現在我是菜鳥第一次改用 SWIFT 編程並使用 urlsession。
代碼
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, URLSessionDelegate, URLSessionDataDelegate, URLSessionTaskDelegate {
//var dataArr:Dictionary<String,String> = [:]
var dataArr : NSMutableArray = NSMutableArray.init()
var myTableview:UITableView = UITableView.init()
let color = UIColor(red: 69/255, green: 57/255, blue: 169/255, alpha: 1.0)
let cellID: String = "customCell"
var progressBar : UIProgressView = UIProgressView.init()
let progressView : UIView = UIView.init(frame: CGRect(x: 100, y: 10, width: 100, height: 20))
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)
{
let uploadProgress:Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print(uploadProgress)
DispatchQueue.main.async {
self.progressBar.progress = uploadProgress
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let textName: UILabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
textName.textColor=UIColor.black
textName.backgroundColor=UIColor.green
textName.text=dataArr[indexPath.row] as? String
print("\(dataArr[indexPath.row])");
textName.font=UIFont.systemFont(ofSize: 14)
cell.addSubview(textName)
progressView.backgroundColor = UIColor.red
progressView.tag=indexPath.row
let customKeys=["type","Facebook","Google","Twitter"];
let customsValues=["uploadFile","Mark","Lary","Goo"];
let customDatas=Dictionary(uniqueKeysWithValues: zip(customKeys,customsValues))
progressBar = UIProgressView.init(frame: CGRect(x: 0, y: 5, width: 100, height: 20))
progressBar.tag=indexPath.row
progressView.addSubview(progressBar)
cell.addSubview(progressView)
uploadImage(data_dict: customDatas, uploadImg: dataArr[indexPath.row] as! String)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let hCell:CGFloat = 50.0
return hCell
}
// override func viewWillAppear(_ animated: Bool) {
// super.viewWillAppear(animated)
// setNeedsStatusBarAppearanceUpdate()
// }
override var preferredStatusBarStyle: UIStatusBarStyle {
// Change font of status bar is white.
.lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
dataArr=["1.jpg","2.jpg","3.jpg"]
//print(dataArr)
let myScreen = UIScreen.main.bounds
let statusHieght = UIApplication.shared.statusBarFrame.height
if #available(iOS 13.0, *) {
let app = UIApplication.shared
let statusBarHeight: CGFloat = app.statusBarFrame.size.height
let statusbarView = UIView()
statusbarView.backgroundColor = color
statusbarView.tintColor = .white
view.addSubview(statusbarView)
statusbarView.translatesAutoresizingMaskIntoConstraints = false
statusbarView.heightAnchor
.constraint(equalToConstant: statusBarHeight).isActive = true
statusbarView.widthAnchor
.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
statusbarView.topAnchor
.constraint(equalTo: view.topAnchor).isActive = true
statusbarView.centerXAnchor
.constraint(equalTo: view.centerXAnchor).isActive = true
} else {
let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
statusBar?.backgroundColor = color
}
UINavigationBar.appearance().barTintColor = color
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
UINavigationBar.appearance().isTranslucent = false
let navBar = UINavigationBar(frame: CGRect(x: 0, y: statusHieght, width: myScreen.size.width, height: 44))
//navBar.isTranslucent=true
//navBar.backgroundColor = .red
let navItem = UINavigationItem(title: "SomeTitle")
let doneItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target:nil , action:#selector(ClickDone))
navItem.rightBarButtonItem = doneItem
navBar.setItems([navItem], animated: false)
self.view.addSubview(navBar)
let AllTopDistance=statusHieght+navBar.frame.size.height
let myView:UIView = UIView.init(frame: CGRect(x: 0, y: AllTopDistance, width: myScreen.size.width, height: myScreen.size.height-AllTopDistance))
myView.backgroundColor = .lightGray
myTableview=UITableView.init(frame: CGRect(x: 0, y: 0, width: myScreen.size.width, height: myScreen.size.height-AllTopDistance))
myTableview.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
print("\(statusHieght) \(myScreen.size.width) \(AllTopDistance)")
myTableview.delegate=self
myTableview.dataSource=self
myTableview.backgroundColor=UIColor.red
myView.addSubview(myTableview)
self.view.addSubview(myView)
}
@objc func ClickDone(){
print("Done")
}
func calculateTopDistance() -> CGFloat{
/// Create view for misure
let misureView : UIView = UIView()
misureView.backgroundColor = .clear
view.addSubview(misureView)
/// Add needed constraint
misureView.translatesAutoresizingMaskIntoConstraints = false
misureView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
misureView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
misureView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
if let nav = navigationController {
misureView.topAnchor.constraint(equalTo: nav.navigationBar.bottomAnchor).isActive = true
}else{
misureView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}
/// Force layout
view.layoutIfNeeded()
/// Calculate distance
let distance = view.frame.size.height - misureView.frame.size.height
/// Remove from superview
misureView.removeFromSuperview()
return distance
}
@objc func uploadImage(data_dict : Dictionary<String,String>, uploadImg : String)
{
print("click \(data_dict)")
let image = UIImage(named: uploadImg)
// generate boundary string using a unique per-app string
let boundary = UUID().uuidString
let config = URLSessionConfiguration.default
//let session = URLSession(configuration: config)
let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
// Set the URLRequest to POST and to the specified URL
var urlRequest = URLRequest(url: URL(string: "http://x.x.x.x/xxx/Labs.php")!)
urlRequest.httpMethod = "POST"
// Set Content-Type Header to multipart/form-data, this is equivalent to submitting form data with file upload in a web browser
// And the boundary is also set here
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
for (key, value) in data_dict {
print(key, value)
let fieldName = key
let fieldValue = value
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"\(fieldName)\"\r\n\r\n".data(using: .utf8)!)
data.append("\(fieldValue)".data(using: .utf8)!)
}
// Add the image data to the raw http request data
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"\(uploadImg)\"\r\n".data(using: .utf8)!)
data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
data.append((image?.jpegData(compressionQuality: 1.0))!)
// End the raw http request data, note that there is 2 extra dash ("-") at the end, this is to indicate the end of the data
// According to the HTTP 1.1 specification https://tools.ietf.org/html/rfc7230
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
// Send a POST request to the URL, with the data we created earlier
session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
if(error != nil){
print("\(error!.localizedDescription)")
}
guard let responseData = responseData else {
print("no response data")
return
}
if let responseString = String(data: responseData, encoding: .utf8) {
print("Response data : \(responseString)")
}
}).resume()
}
}
?? 如何通過單元格/文件在 uitableview 中定義 URLSESSION 更新進度視圖 謝謝。
我很好奇你是如何使用 AFNetworking 在 Objective-C 中做到的。 至少在概念上,使用 URLSession 在 Swift 中實現應該沒有太大區別。
恕我直言,您關於更新進度的主要問題是,您與所有單元格的單個 UIView 實例共享 progressView 變量。
cell.addSubview(progressView)
不僅將您的 progressView 添加到該單元格,它還從其他單元格中刪除您的 progressView,因為一個視圖只能有一個父視圖。tableView(_:cellForRowAt indexPath:)
一個self.progressBar.progress = uploadProgress
您將始終更新上次初始化的進度條,因為您沒有對其他進度條的引用。為了讓它以一種干凈的方式工作,我建議您對 MVVM 架構進行一些研究。
對於快速和骯臟的修復:
刪除這些行:
var progressBar : UIProgressView = UIProgressView.init()
let progressView : UIView = UIView.init(frame: CGRect(x: 100, y: 10, width: 100, height: 20))
添加變量:
var uploadTasks: [URLSessionDataTask: IndexPath] = [:]
添加一個輔助函數來計算 viewTag:
func viewTag(for indexPath: IndexPath) -> Int {
return indexPath.row + 1000
}
將您的tableView(_:cellForRowAt indexPath:)
更改為:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let textName: UILabel = UILabel.init(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
textName.textColor=UIColor.black
textName.backgroundColor=UIColor.green
textName.text=dataArr[indexPath.row] as? String
print("\(dataArr[indexPath.row])");
textName.font=UIFont.systemFont(ofSize: 14)
cell.addSubview(textName)
let progressView = UIView(frame: CGRect(x: 100, y: 10, width: 100, height: 20))
progressView.backgroundColor = UIColor.red
let customKeys=["type","Facebook","Google","Twitter"];
let customsValues=["uploadFile","Mark","Lary","Goo"];
let customDatas=Dictionary(uniqueKeysWithValues: zip(customKeys,customsValues))
let progressBar = UIProgressView.init(frame: CGRect(x: 0, y: 5, width: 100, height: 20))
progressBar.tag = viewTag(for: indexPath)
progressView.addSubview(progressBar)
cell.addSubview(progressView)
uploadImage(data_dict: customDatas, indexPath: indexPath)
return cell
}
將您的 uploadImage 方法更改為:
@objc func uploadImage(data_dict : Dictionary<String,String>, indexPath : IndexPath) {
print("click \(data_dict)")
let uploadImg = dataArr[indexPath.row] as! String
let image = UIImage(named: uploadImg)
...
let task = session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
...
})
uploadTasks[task] = indexPath
task.resume()
}
將您的 urlSession 委托方法更改為:
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
let uploadProgress:Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print(uploadProgress)
guard let indexPath = uploadTasks[task] else { return }
let viewTag = viewTag(for: indexPath)
guard let progressBar = self.view.viewWithTag(viewTag) as? UIProgressView else { return }
DispatchQueue.main.async {
progressBar.progress = uploadProgress
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.