In this code we used "alamofire" for download the image but present there i want to replace the image so please help me. When i get response then image present then i have get error code 516 (Already Image existing) so please help me after get response.
i want replace the old image or delete old image.
func setUI() {
self.btnCancel.layer.borderWidth = 1.0
self.btnCancel.layer.cornerRadius = 3.0
self.btnCancel.addShadowView()
print("-------------------------------- method Call")
if let url = NSURL(string: strFileName) {
print(url)
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
self.request = Alamofire.download(.GET, url, parameters: nil, encoding: ParameterEncoding.URL,destination:destination)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes read on main queue: \(totalBytesRead)")
print("Progress on main queue: \(Float(totalBytesRead) / Float(totalBytesExpectedToRead))")
print("totalBytesExpectedToRead",totalBytesExpectedToRead)
self.CountPercentage.text! = String(format: "%.f%%",self.viewProgressBar.progress * 100)
self.viewProgressBar.progress = (Float(totalBytesRead) / Float(totalBytesExpectedToRead))
}
}
.response { request, response, _, error in
print("\(request?.URL)") // original URL request
print(error)
if !(error == nil) {
if !(error!.code != NSURLErrorCancelled) {
print("cancel----------")
} else if (error!.code == 516) {
print("fileURL: \(destination(NSURL(string: "")!, response!))")
let filePath = destination(NSURL(string: "")!, response!)
self.alertAction("File downloaded successfully.", filePath: filePath)
} else {
CommonMethods.sharedInstance.showAlertWithMessage((error?.localizedDescription)!, withController: self)
}
} else {
print("fileURL: \(destination(NSURL(string: "")!, response!))")
let filePath = destination(NSURL(string: "")!, response!)
self.alertAction("File downloaded successfully.", filePath: filePath)
}
}
}
}
Related
I am getting getting multiple PDF urls from server response and showing them in tableview with download option for each cell.
I am able to download each pdf file only once, But, Tried to second time download, It is showing already downloaded error.
How to fix this?
Here is my code
func downloadButtonTapped(index: Int) {
let finalUrlStr = "(dataResponse?[index].brochure)")
let fileURL = URL(string: finalUrlStr)
let fileName = String((fileURL!.lastPathComponent)) as NSString
// Create destination URL
let documentsUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
//Create URL to the source file you want to download
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
LoadingView.show()
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
do {
//Show UIActivityViewController to save the downloaded file
let contents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for indexx in 0..<contents.count {
if contents[indexx].lastPathComponent == destinationFileUrl.lastPathComponent {
let activityViewController = UIActivityViewController(activityItems: [contents[indexx]], applicationActivities: nil)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
self.present(activityViewController, animated: true, completion: nil)
LoadingView.hide()
}
}
}
}
catch (let err) {
// DispatchQueue.main.async {
print("error: \(err.localizedDescription)")
LoadingView.hide()
self.showBasicAlert(title: "\(err.localizedDescription)", message: "")
// }
}
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
LoadingView.hide()
self.showBasicAlert(title: "\(writeError.localizedDescription)", message: "")
}
} else {
print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "")")
self.showBasicAlert(title: "\(error?.localizedDescription ?? "")", message: "")
}
}
task.resume()
}
Even though, PDF not downloaded even one time before download file, activitycontroller displaying and If we close that without download/save file, Again trying to download, Same error message showing like already exist file
How to download multiple times like whenever user taps on download option, It should download the pdf file.
Also after downloaded pdf, I need to show open pdf from external not inside app
Any suggestions?
I have fixed it by myself by removing condition.
Now I am able to download whenever user tap on download button.
Here is the code.
func downloadButtonTapped(index: Int) {
// print("index \(index)")
let finalUrlStr = "(dataResponse?[index].brochure)")
let fileURL = URL(string: finalUrlStr)
if let fileUrl = fileURL {
let fileName = String((fileUrl.lastPathComponent)) as NSString
// Create destination URL
let documentsUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
//Create URL to the source file you want to download
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileUrl)
LoadingView.show()
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
//Show UIActivityViewController to save the downloaded file
let contents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for indexx in 0..<contents.count {
if contents[indexx].lastPathComponent == destinationFileUrl.lastPathComponent {
let activityViewController = UIActivityViewController(activityItems: [contents[indexx]], applicationActivities: nil)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
self.present(activityViewController, animated: true, completion: nil)
LoadingView.hide()
}
}
}
}
catch (let err) {
print("error: \(err.localizedDescription)")
DispatchQueue.main.async {
LoadingView.hide()
self.showBasicAlert(title: "\(err.localizedDescription)", message: "")
}
}
}
}
task.resume()
}
}
I have more than 500 image links I want to download those images and store locally in app document directory when app starts. I am using Almofire for download but I am getting error like
"URLSession task was cancelled" and Request timeOut
func downloadAllImages(images:[String: String], retryCount: Int = 0,completion: #escaping((Bool)->Void)){
var success: Bool = true
var failedImages = [String: String]()
for (localName, severPath) in images {
self.dispatchGroup.enter()
let destination: DownloadRequest.Destination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent(localName)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
let path = severPath.replacingOccurrences(of: "\\", with: "/").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
//AF.sessionConfiguration.httpShouldSetCookies = false
AF.download(path, to: destination).response { response in
switch response.result {
case .success(_):
break
case .failure(let error):
if response.response?.statusCode != 404 {
success = false
failedImages[localName] = path
print("Image Download Error = \(error.localizedDescription)")
}
break
}
debugPrint(response)
self.dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
//retry If some Images failed to download
if failedImages.isEmpty || retryCount >= self.maximumRetryCount {
completion(success)
}else {
self.downloadAllImages(images: failedImages, retryCount: retryCount + 1) { (success) in
completion(success)
}
}
}
}
images dictionary contains
localName as key
serverPath as value
AFImageDownloaders have limit of active downloads, and I believe changing maximumActiveDownloads or something similar in your API will fix that. The new downloads just cancel the previous ones. But it's better to download them in chunks.
For example this one is for ImageDownloader
public init(session: Session,
downloadPrioritization: DownloadPrioritization = .fifo,
maximumActiveDownloads: Int = 4,
imageCache: ImageRequestCache? = AutoPurgingImageCache()) {
precondition(!session.startRequestsImmediately, "Session must set `startRequestsImmediately` to `false`.")
self.session = session
self.downloadPrioritization = downloadPrioritization
self.maximumActiveDownloads = maximumActiveDownloads
self.imageCache = imageCache
}
UPD:
The limit is not on AF, but URLSession's. And one AF downloader uses one URLSession. You have to pass custom URLSessionConfigurations to handle more active downloads HTTPMaximumConnectionsPerHost. And pass it AF Session class
I am downloading the zip file using the Alamofire in my ios(swift4) application. I am able to download the file serially using Alamofire.
But I also want to show the one progress bar for the all the downloaded files. Means If I have 4 zip files and when all the file is downloaded then the progress should be 100%.
Till I have tried below code, which gives a progress value for each of the url and progress is shown as one file downloaded showing progress as 100% then again it start from 0 for second url and when second url is downloaded then progress is shown 100% complete.
Please guide me for this. I want to get progress value as 100% when all the files are downloaded using Alamofire.
Can it be possible with Alamofire?
CODE:
func serialZipFileDownload(downloadPath: String){
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let name = self.offlineDownloadFileName?[urlCount]
let currentVideoURL = documentsURL.appendingPathComponent(name ?? "Default.zip")
let str = downloadPath
let urlString = str.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: urlString ?? "")
if super.isConnectedToNetwork() == true {
let manager = Alamofire.SessionManager.default
let headers = ["Accept-Encoding" : ""]
manager.request(url ?? "", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).downloadProgress { (progress) in
print(progress.fractionCompleted)
DispatchQueue.main.async{
self.progressDownload.setProgress((Float(progress.fractionCompleted)), animated: true)
let per = round((Float(progress.fractionCompleted)) * 100)
self.lblDownloadPercent.text = "\(Int(per))%"
}
}.responseData { (response) in
switch (response.result){
case .success(_) :
print(response)
print(response.result.value!)
print(response.result.description)
if let data = response.result.value {
do {
try data.write(to: currentVideoURL)
self.showToast(message: "File downloaded successfully")
}
catch {
print("Something went wrong!")
}
}
case .failure(let error) :
print(response)
if error._code == NSURLErrorNetworkConnectionLost {
DispatchQueue.main.async {
super.showPopup(title: msgStruct.networkTitle, message: msgStruct.noInternet)
}
}
else if error._code == NSURLErrorTimedOut {
DispatchQueue.main.async {
super.showPopup(title: msgStruct.networkTitle, message: msgStruct.noInternet)
}
}
else if error._code == NSURLErrorDownloadDecodingFailedMidStream {
print("error",error.localizedDescription)
}
break
}
}
}
else{
super.showPopup(title: msgStruct.networkTitle, message: msgStruct.noInternet)
}
You can do it like this:
Maintain a global variable - tatalPercentage some other swift class.
static let tatalPercentage = 0
tatalPercentage = tatalPercentage + Int(per/4)
self.lblDownloadPercent.text = "\(tatalPercentage) %"
I have table view that download video file for each cell. Here is my code for downloading video file.
func beginItemDownload(id:String,url:String,selectRow:Int) {
let pathComponent = "pack\(self.packID)-\(selectRow + 1).mp4"
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let folderPath: URL = directoryURL.appendingPathComponent("Downloads", isDirectory: true)
let fileURL: URL = folderPath.appendingPathComponent(pathComponent)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
let url = URL(string:url)
Alamofire.download(
url!,
method: .get,
parameters: nil,
encoding: JSONEncoding.default,
headers: nil,
to: destination).downloadProgress(closure: { (progress) in
DispatchQueue.main.async {
if progress.fractionCompleted < 1 {
print(Float(progress.fractionCompleted))
}
if progress.fractionCompleted == 1 {
print("Completed")
}
}
}).response(completionHandler: { (defaultDownloadResponse) in
if let destinationUrl = defaultDownloadResponse.destinationURL {
DispatchQueue.main.async {
print("destination url -****",destinationUrl.absoluteString)
}
}
if let error = defaultDownloadResponse.error {
debugPrint("Download Failed with error - \(error)")
return
}
})
}
When tapping download button for each tableview cell I can download video file and assign progress value for each cell. But now I want to cancel download request for this cell when tapping on cancel button in each cell, .
I search different solution for this issue but I can't find any solution for cancelling one request with a specific url string. How can solve this issue.
Thanks for all reply.
Not tested but should work, use originalRequest(which is the original request when the task was created) or optionally currentRequest(which is the request currently being handled) to locate the specific task you want cancel:
func cancelSpecificTask(byUrl url:URL) {
Alamofire.SessionManager.default.session.getAllTasks{sessionTasks in
for task in sessionTasks {
if task.originalRequest?.url == url {
task.cancel()
}
}
}
}
Or only cancel download task:
func cancelSepcificDownloadTask(byUrl url:URL) {
let sessionManager = Alamofire.SessionManager.default
sessionManager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
for task in downloadTasks {
if task.originalRequest?.url == url {
task.cancel()
}
}
}
Though luiyezheng's answer is really good and should do the job it is sometimes overlooked by developers (by me for example) that Alamofire.download() actually returns DownloadRequest which could be stored somewhere if needed and later cancel() `ed:
let request = Alamofire.download("http://test.com/file.png")
r.cancel()
I have a question,and I want to show the progressView when I download the Image to my local file
I write a function to download Image, and take other question as reference.
but I don't know how to use URLSessionDownloadTak or other download progress function in my function.
This is my download function code:
func ImageFromUrl(imageView:UIImageView,url:String,chatroomId:String) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Image)/")
// create a name for your image
let fileName = url + ".jpg"
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName)
let urlString = URL(string: url)
if let image = UIImage(contentsOfFile: fileURL.path)
{
imageView.image = image
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: urlString!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
if data != nil
{
if let image = UIImage(data: data!)
{
if !FileManager.default.fileExists(atPath: fileURL.path) {
if let jpegData = UIImageJPEGRepresentation(image, 0.001)
{
do {
try jpegData.write(to: fileURL, options: .atomic)
} catch {
debug(object: error)
}
}
} else {
debug(object:"file already exists")
}
DispatchQueue.main.async {
imageView.image = image//UIImage(data: data!)
}
}
}
}
}
If you want a simple solution instead of NSURLSession, I would suggest Alamofire. It has a simple method to do this kind of task.
For more information https://github.com/Alamofire/Alamofire
Alamofire.download(urlString)
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.result.value {
let image = UIImage(data: data)
}
}