从 url 下载前如何获取文件大小?
How to get file size before downloading from url?
我尝试在点击单元格后 AlertView
下载前显示文件大小:
var fileSize = 0
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let url = URL(string: "http://ex.com/\(indexPath.row).mp3")!
getDownloadSize(url: url, completion: { (size, error) in
if error != nil {
print("An error occurred when retrieving the download size: \(error!.localizedDescription)")
} else {
print("The download size is \(size).")
self.fileSize = Int(size)
}
})
// Create the alert controller
let alertController = UIAlertController(title: nil, message: "Size - \(self.fileSize) MB", preferredStyle: UIAlertControllerStyle.actionSheet)
etc
}
func getDownloadSize(url: URL, completion: @escaping (Int64, Error?) -> Void) {
let timeoutInterval = 5.0
var request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: timeoutInterval)
request.httpMethod = "HEAD"
URLSession.shared.dataTask(with: request) { (data, response, error) in
let contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
completion(contentLength, error)
}.resume()
}
但是当我第一次点击单元格时,我得到了大小 - 0 MB。如果我下次单击任何单元格,我会从之前的 url(上一个单元格)中获取大小。如何解决?
URL 数据任务是异步的。您的代码不会等到它完成才显示对话框。
这就像派人去花园数一数他看到地上有多少苹果,然后您就可以把这个数字写在一张纸上。您告诉那个人去数数并将结果放入一个盒子中,该盒子当前存储数字零。该人一离开,您就打开盒子并写下您看到的数字。然而这个人甚至还没有到花园里,也没有数过苹果。当这个人returns,他按照你告诉他的去做,把数出的苹果数放到盒子里。现在你再次派人,这次是数数他在花园里看到的梨的数量。再一次,当这个人离开时,你打开盒子并记下你在那里看到的数字,但这仍然是数苹果的数字,因为这个人甚至没有机会更新那个数字。
一旦获取结果,您提供给 getDownloadSize()
的块将 运行,但下面的代码会在调用 getDownloadSize()
后立即调用 运行s,它不会等到块执行完。
更改它不是一个好主意,因为获取结果可能需要几秒钟到几分钟不等。如果在获取结果之前代码的执行会阻塞,那么您的整个应用程序也会在这段时间内阻塞(您的 UI 将完全冻结,无法进行用户交互)。
您正在检查 didSelectRowAt 方法中的文件大小,只有当您 select 该行时才会调用该方法。您应该改为在 cellForRowAt 方法中延迟加载单元格中的变量。但注意不要在主线程上进行下载。
我尝试在点击单元格后 AlertView
下载前显示文件大小:
var fileSize = 0
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let url = URL(string: "http://ex.com/\(indexPath.row).mp3")!
getDownloadSize(url: url, completion: { (size, error) in
if error != nil {
print("An error occurred when retrieving the download size: \(error!.localizedDescription)")
} else {
print("The download size is \(size).")
self.fileSize = Int(size)
}
})
// Create the alert controller
let alertController = UIAlertController(title: nil, message: "Size - \(self.fileSize) MB", preferredStyle: UIAlertControllerStyle.actionSheet)
etc
}
func getDownloadSize(url: URL, completion: @escaping (Int64, Error?) -> Void) {
let timeoutInterval = 5.0
var request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: timeoutInterval)
request.httpMethod = "HEAD"
URLSession.shared.dataTask(with: request) { (data, response, error) in
let contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
completion(contentLength, error)
}.resume()
}
但是当我第一次点击单元格时,我得到了大小 - 0 MB。如果我下次单击任何单元格,我会从之前的 url(上一个单元格)中获取大小。如何解决?
URL 数据任务是异步的。您的代码不会等到它完成才显示对话框。
这就像派人去花园数一数他看到地上有多少苹果,然后您就可以把这个数字写在一张纸上。您告诉那个人去数数并将结果放入一个盒子中,该盒子当前存储数字零。该人一离开,您就打开盒子并写下您看到的数字。然而这个人甚至还没有到花园里,也没有数过苹果。当这个人returns,他按照你告诉他的去做,把数出的苹果数放到盒子里。现在你再次派人,这次是数数他在花园里看到的梨的数量。再一次,当这个人离开时,你打开盒子并记下你在那里看到的数字,但这仍然是数苹果的数字,因为这个人甚至没有机会更新那个数字。
一旦获取结果,您提供给 getDownloadSize()
的块将 运行,但下面的代码会在调用 getDownloadSize()
后立即调用 运行s,它不会等到块执行完。
更改它不是一个好主意,因为获取结果可能需要几秒钟到几分钟不等。如果在获取结果之前代码的执行会阻塞,那么您的整个应用程序也会在这段时间内阻塞(您的 UI 将完全冻结,无法进行用户交互)。
您正在检查 didSelectRowAt 方法中的文件大小,只有当您 select 该行时才会调用该方法。您应该改为在 cellForRowAt 方法中延迟加载单元格中的变量。但注意不要在主线程上进行下载。