So I ran this code using swift and the issue that I am having is that it's not working on the first try it compiles the project. However, when I stop the project and run it again it works perfectly fine and I do repeat this several times and the issue doesn't occur anymore. More specifically, when the project opens and I press a button on the app it goes to the error that I show below:
This is the error that I get when I run it for the first time
"Thread 1: Fatal error: 'try!' expression unexpectedly raised an
error: Error Domain=NSCocoaErrorDomain Code=260 "The file “.tmp”
couldn’t be opened because there is no such file."
UserInfo={NSFilePath=/.tmp, NSUnderlyingError=0x60000335d9b0 {Error
Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}"
This error shows up on the line where let contentstring is created. I check the value of contentstring and I get that contentstring = (NSString) 0x0000000000000000. When running the program multiple times it gives me a valid value and it works perfectly fine.
I am not sure why this error occurs only once when the button is pressed and what is a solid approach to this problem.
import UIKit
class KresgePorter: UIViewController, UITableViewDataSource, UITableViewDelegate {
var printString: String!
var array: [String] = []
var count: Int = 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: false)
}
override func viewDidLoad() {
super.viewDidLoad()
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
var nameTXT = ""
var documentsDir = ""
let website = some string url
guard let url1 = URL(string: website) else { return }
//This portion of the code focuses on creating a download task with a completion handler
//Completion handler moves the downloaded file to the app's directory
let downloadTask = URLSession.shared.downloadTask(with: url1) {
urlOrNil, responseOrNil, errorOrNil in
// check for and handle errors:
// * errorOrNil should be nil
// * responseOrNil should be an HTTPURLResponse with statusCode in 200..<299
print("Went into the let\n")
guard let fileURL = urlOrNil else { return }
do {
let documentsURL = try
FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent)
let filename = fileURL.lastPathComponent
let fileName2 = URL(fileURLWithPath: filename).deletingPathExtension().lastPathComponent
nameTXT = fileName2
print("the content of nameTXT is: \(nameTXT)")
try FileManager.default.moveItem(at: fileURL, to: savedURL)
} catch {
print ("file error: \(error)")
}
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
documentsDir = paths.firstObject as! String
print("Path to the Documents directory\n\(documentsDir)")
}
downloadTask.resume()
//If you want to receive progress updates as the download proceeds, you must use a delegate.
var urlSession = URLSession(configuration: .default, delegate: self as? URLSessionDelegate, delegateQueue: nil)
func startDownload(url1: URL){
print("Went into the startDownload function\n")
let downloadTask = urlSession.downloadTask(with: url1)
//let fname = downloadTask.response?.suggestedFilename
downloadTask.resume()
}
startDownload(url1: url1)
/*-----------------------------------------------------------------------------------------------------*/
usleep(270000)
let directPath = documentsDir + "/" + nameTXT + ".tmp"
let url = URL(fileURLWithPath: directPath)
let contentString = try! NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue)
printString = contentString as String
let fullName = printString
array = fullName!.components(separatedBy: "\n")
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "breakfast", for: indexPath)
cell.textLabel?.text = array[indexPath.row]
return cell
}
}
I shouldn't use try! in production code!
let contentString = try! NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue)
convert to this:
do {
let contentString = try? String( url, encoding: .utf8)
} catch {
print(error)
}
The actual problem is that:
let directPath = documentsDir + "/" + nameTXT + ".tmp"
let url = URL(fileURLWithPath: directPath)
yields "/.tmp". this is an invalid URL.
This is because of both documentsDir and nameTXT are empty.
So, the core reason is that you call
let directPath = documentsDir + "/" + nameTXT + ".tmp"
let url = URL(fileURLWithPath: directPath)
outside of the server response callback.
Just move your code from
// If you want to receive progress updates as the download until
array = fullName!.components(separatedBy: "\n")
into closure right after this line:
print("Path to the Documents directory\n\(documentsDir)")
your closure is launched asynchronously.
Related
In my application the user is able to select an image within his gallery and save it in a UIMAGEVIEW now the problem is that when I save that image in cloudkit gives me the following error
"Call can throw, but it is not marked with 'try' and the error is not handled"
#IBAction func Save(_ sender: Any) {
let codig = code.text
let precio = price.text
let imagen = imageCover.image
let record = CKRecord(recordType: "Productos", zoneID: zona.zoneID)
record.setObject(codig as __CKRecordObjCValue?, forKey: "code")
record.setObject(precio as __CKRecordObjCValue?, forKey: "costo")
let mngr = FileManager.default
let dir = mngr.urls(for: .documentDirectory, in: .userDomainMask)
let file = dir[0].appendingPathComponent("myimage").path
imagen?.jpegData(compressionQuality: 0.5)?.write(to: file as! URL)
let imgURL = NSURL.fileURL(withPath: file)
let imageAsset = CKAsset(fileURL: imgURL)
record.setObject(imageAsset, forKey: "imagecover")
self.navigationItem.backBarButtonItem?.isEnabled = false
database.save(record) { (record, error) in
DispatchQueue.main.async {
self.navigationItem.backBarButtonItem?.isEnabled = true
if let error = error {
print("Error \(error.localizedDescription)")
} else {
print("Save")
self.navigationController?.popViewController(animated: true)
}
}
}
Your problem is the following line:
imagen?.jpegData(compressionQuality: 0.5)?.write(to: file as! URL)
As you can see in the documentation(https://developer.apple.com/documentation/foundation/data/1779858-write) the function write(to:) can throw an error. You need to handle the error by either ignoring it
try? <function that throws error>
or by catching it using a do..catch block:
do {
try <function that throws error>
} catch {
// Handle error
}
I'm using 'AlamoFireImage' to download my image files.
And after that, I use NSFileManager and CreateFile method to save them in a directory.
But when I try to retrieve the saved images, It only returns the first File. While It should have saved 15 images.
Here's my function for saving Image Files :
func getImage(url: String) {
Alamofire.request("https://www.tandori.ir/uploads/categories/" + url).responseImage { (response) in
if response.result.value != nil {
do {
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(url)
let image = UIImage(named: url)
let imageData = image?.jpegData(compressionQuality: 0.2)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
print(paths)
}
catch let error as NSError {
print(error)
}
}
}
}
And this is my function for downloading them :
func launchApp() {
let imgTitiles = UserDefaults.standard.array(forKey: "imgsArray")!
for pic in imgTitiles {
self.getImage(url: pic as! String)
print("done")
}
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewController(withIdentifier: "mainTab") as! TandoriTabView
self.present(resultViewController, animated: true)
}
When I try to retrieve the saved images, I get this error on Console :
"BOMStream BOMStreamWithFileAndSys(int, off_t, size_t, int, char *, BomSys *): read: No such file or directory"
I'm trying to Show these images in a collection view.
Here's my code in my ViewController :
//Get Images Directory Path Function.
func getDirectoryPath() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory
}
//Get Images Function.
func getImage(name : String) -> String {
_ = FileManager.default
let imagePAth = (self.getDirectoryPath() as NSString).appendingPathComponent(name)
return imagePAth
}
//Show Images in collectionView cells function.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = categoriesCollection.dequeueReusableCell(withReuseIdentifier: "categories", for: indexPath) as! categoriesCell
let imageAddress = getImage(name: imgTitiles[indexPath.row] as! String) //TheRealShit
cell.categoryImage.image = UIImage(contentsOfFile: imageAddress)
return cell
}
What seems to be the Problem?
Thanks in advance!
Actually your using Alamofire downloading images are in asynchronously. Due to this you are only few images when you are showing viewcontroller. Modify your code to getImage() synchronously in below code. I hope it will work for you.
func getImage(url: String) {
if let image = UIImage(named: url) {
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(url)
let imageData = image?.jpegData(compressionQuality: 0.2)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
print(paths)
}
}
I am in desperate need of help.
I am trying to create an app which allows the user to save the pdf file from a link such as the example one I gave in the subjectLinks array, all those links point to a pdf page and I am trying to download it and save it in my app. So far, I have scoured everywhere and found a way to do it using the Files app, so what I'm doing in the code is downloading the data of the pdf and opening it using UIDocument and presentPreview to display it and I have managed to allow the user to share the downloaded file and save it to Files as well.
However the problem arises as I want to make it so that when the user clicks download the file is automatically saved to the Files app in a directory so that the user does not need to click the option button then choose Save to Files and then look for where to save it. Is that possible??
If that is not possible, at least when the user chooses the option button and clicks Save to Files, it would automatically create a separate directory where the user can see and pdf file can be saved?
I want to do this as most times, when Save to Files is chosen, saving 'On My iPhone' is not available as there is no directory or such present so it can only be saved to google drive or iCloud Drive and this is a major inconvenience.
Sorry for the long post. BUT I WOULD BE EXTREMELY GRATEFUL IF ANYONE COULD HELP SOLVE MY PROBLEM. THANK YOU SOOOOO MUCH IN ADVANCE :)
P.S everything in my code works perfectly fine so far, its just I am absolutely clueless as to how to implement the features I have outlines above?
import UIKit
import StoreKit
class TableViewController: UITableViewController {
let documentInteractionController = UIDocumentInteractionController()
let subjectLinks = ["https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Accounting%20(9706)/2015%20Jun/9706_s15_qp_42.pdf", "https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Economics%20(9708)/2017%20Jun/9708_s17_qp_12.pdf", "https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Mathematics%20(9709)/2018-May-June/9709_s18_qp_12.pdf"]
override func viewDidLoad() {
super.viewDidLoad()
documentInteractionController.delegate = self as? UIDocumentInteractionControllerDelegate
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subjectLinks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = subjectLinks[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
// 1
let shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Download" , handler: { (action:UITableViewRowAction, indexPath: IndexPath) -> Void in
// 2
let downloadMenu = UIAlertController(title: nil, message: "Download this paper", preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
downloadMenu.addAction(UIAlertAction(title: "Download", style: UIAlertActionStyle.destructive, handler: { action in self.storeAndShare(withURLString: self.subjectLinks[indexPath.row])}))
downloadMenu.addAction(cancelAction)
self.present(downloadMenu, animated: true, completion: nil)
})
// 3
let rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Rate" , handler: { (action:UITableViewRowAction, indexPath:IndexPath) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.default, handler: {action in SKStoreReviewController.requestReview()})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.present(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
}
extension TableViewController {
/// This function will set all the required properties, and then provide a preview for the document
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
/// This function will store your document to some temporary URL and then provide sharing, copying, printing, saving options to the user
func storeAndShare(withURLString: String) {
guard let url = URL(string: withURLString) else { return }
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let fileManager = FileManager.default
do {
let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = documentDirectory.appendingPathComponent("fileName.pdf")
try data.write(to: fileURL)
DispatchQueue.main.async {
self.share(url: fileURL)
}
} catch {
print(error)
}
}.resume()
}
}
extension TableViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
Example of download any pdf file and automatically save inside files folder of iPhone.
let urlString = "https://www.tutorialspoint.com/swift/swift_tutorial.pdf"
let url = URL(string: urlString)
let fileName = String((url!.lastPathComponent)) as NSString
//Mark: Create destination URL
let documentsUrl:URL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
//Mark: Create URL to the source file you want to download
let fileURL = URL(string: urlString)
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
//Mark: Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
do {
//Mark: 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)
self.present(activityViewController, animated: true, completion: nil)
}
}
}
catch (let err) {
print("error: \(err)")
}
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
} else {
print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "")")
}
}
task.resume()
Step #1: Need to add permission in info.plist
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
Step #2: Download document from server url[any document]
func downloadPdf(sender:UIButton) {
DispatchQueue.main.async {
//Do UI Code here.
let pdfUrl = self.myOrderListModel?.myorderList?[sender.tag].invoiceUrl ?? ""
guard let fileURL = URL(string: pdfUrl) else { return }
var originalUrlStr : String = ""
print(fileURL.pathExtension)
if fileURL.pathExtension == ""{
originalUrlStr = pdfUrl + ".pdf"
} else {
originalUrlStr = pdfUrl
}
guard let originalUrl = URL(string: originalUrlStr) else { return }
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
let downloadTask = urlSession.downloadTask(with: originalUrl)
downloadTask.resume()
}
}
extension InvoiceViewController: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("File Downloaded Location- ", location)
guard let url = downloadTask.originalRequest?.url else {
return
}
let docsPath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let destinationPath = docsPath.appendingPathComponent(url.lastPathComponent)
try? FileManager.default.removeItem(at: destinationPath)
do{
try FileManager.default.copyItem(at: location, to: destinationPath)
print("File Downloaded Location- ", destinationPath)
DispatchQueue.main.async {
let urlString: String = destinationPath.absoluteString
self.saveInvoiceToDevice(filePath: urlString)
}
}catch let error {
print("Copy Error: \(error.localizedDescription)")
}
}
}
Step #3: Save downloaded file in Device "Files" Folder
func saveInvoiceToDevice(filePath : String) {
let fileURL = URL(string: filePath)
if FileManager.default.fileExists(atPath: fileURL!.path){
let url = URL(fileURLWithPath: fileURL!.path)
let activityViewController: UIActivityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView=self.view
//If user on iPad
if UIDevice.current.userInterfaceIdiom == .pad {
if activityViewController.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
}
}
self.present(activityViewController, animated: true, completion: nil)
}
else {
debugPrint("document was not found")
}
}
I have a custom struct Information. for the property image(string) I want to insert the path of the document directory where the image is saved. When i try to use the UserDefaults to save the struct array, it is saved successfully and also retrieved. But when i use the path to retrieve the image from the document directory it shows the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value.
And when I use the if-else block to catch the exception, No image is displayed on the tableview.
Below is my code:
struct Information{
var image : String
var content : String?
var url : String?
init(image:String,content:String?,url:String?){
self.image = image
self.content = content
self.url = url
}
init(dictionary : [String:String]) {
self.image = dictionary["image"]!
self.content = dictionary["content"]!
self.url = dictionary["url"]!
}
var dictionaryRepresentation : [String:String] {
return ["image" : image, "content" : content!, "url" : url!]
}
}
And my View Controller:
override func viewDidAppear(_ animated: Bool) {
savePath()
loadDefaults()
tableView.reloadData()
}
func saveDefaults()
{
let cfcpArray = information.map{ $0.dictionaryRepresentation }
UserDefaults.standard.set(cfcpArray, forKey: "cfcpArray")
}
func loadDefaults()
{
information = (UserDefaults.standard.object(forKey: "cfcpArray") as! [[String:String]]).map{ Information(dictionary:$0) }
for info in information{
print(info)
}
}
func savePath(){
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
// Get the Document directory path
let documentDirectorPath:String = paths[0]
// Create a new path for the new images folder
imagesDirectoryPath = documentDirectorPath + "/ImagePicker"
var objcBool:ObjCBool = true
let isExist = FileManager.default.fileExists(atPath: imagesDirectoryPath, isDirectory: &objcBool)
// If the folder with the given path doesn't exist already, create it
if isExist == false{
do{
try FileManager.default.createDirectory(atPath: imagesDirectoryPath, withIntermediateDirectories: true, attributes: nil)
}catch{
print("Something went wrong while creating a new folder")
}
}
tableView.reloadData()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the edited.
guard let selectedImage = info[UIImagePickerControllerEditedImage] as? UIImage
else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
image = selectedImage
dismiss(animated: true, completion: nil)
saveImage()
}
func saveImage(){
// Save image to Document directory
var imagePath = Date().description
imagePath = imagePath.replacingOccurrences(of: " ", with: "")
imagePath = imagesDirectoryPath + "/\(imagePath).png"
path = imagePath
// print(path!)
let data = UIImagePNGRepresentation(image)
let success = FileManager.default.createFile(atPath:path!, contents: data, attributes: nil)
information.append(Information(image:path!, content:" ", url: " "))
saveDefaults()
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "TableViewCell"
/*Because you created a custom cell class that you want to use, downcast the type of the cell to your custom cell subclass, MealTableViewCell.*/
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier , for: indexPath) as? TableViewCell
else{
fatalError("The dequeued cell is not an instance of MealTableViewCell.")
}
let info = information[indexPath.row]
if let data = FileManager.default.contents(atPath: info.image)
{
let decodeimage = UIImage(data: data)
cell.photos.image = decodeimage
}
else{
print("Not displaying image")
}
// cell.photos.image = UIImage(data: data!)
return cell
}
Any suggestions is really appreciated. Thank you.
Don't do that. The URL to the documents folder changes periodically for security reasons.
Save a relative path – or just the file name – and after reading the data get the current documents URL and append the path.
Note: NSSearchPathForDirectoriesInDomains is outdated. Use url(for:in:appropriateFor:create:) and the URL related API of FileManager
PS: Why are content and url optionals although the dictionary initializer passes always non-optional values?
Here is the working code. Tested.
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
And to save the image :
// Save image to Document directory
var imagePath = Date().description
imagePath = imagePath.replacingOccurrences(of: " ", with: "")
imagePath = "/\(imagePath).png"
let relpath = getDocumentsURL()
let relativepath = relpath.appendingPathComponent(imagePath)
let data = UIImagePNGRepresentation(image)
let success = FileManager.default.createFile(atPath: relativepath.path , contents: data, attributes: nil)
I got many lists of invoice file at my table view as well as many download buttons at each cell.When I clicked one of it,it will download the invoice file.But,the problem is the server response suggested file name is "invoice.pdf" at every file I downloaded.So,I need to edit the file name manually before I save to document after it was downloaded.So,how to edit the file name manually after it was download successfully and save it in document as temporaryurl without using Alamofire.Request.suggestedDownloadDestination.
Here is my download function.
func downloadInvoice(invoice: Invoice, completionHandler: (Double?, NSError?) -> Void) {
guard isInvoiceDownloaded(invoice) == false else {
completionHandler(1.0, nil) // already have it
return
}
let params = [
"AccessToken" : “xadijdiwjad12121”]
// Can’t use the destination file anymore because my server only return one file name “invoice.pdf” no matter which file i gonna download
// So I have to manually edit my file name which i saved after it was downloaded.
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
// So I have to save file name like that ““2016_04_02_car_invoice_10021.pdf” [Date_car_invoice_timestamp(Long).pdf]
// Please look comment on tableView code
Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders?.updateValue("application/pdf",forKey: "Content-Type")
Alamofire.download(.POST, invoice.url,parameters:params, destination: destination)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
print(totalBytesRead)
dispatch_async(dispatch_get_main_queue()) {
let progress = Double(totalBytesRead) / Double(totalBytesExpectedToRead)
completionHandler(progress, nil)
}
}
.responseString { response in
print(response.result.error)
completionHandler(nil, response.result.error)
}
}
Here is the table view which gonna check downloaded file and when it click,shown on open in feature.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let invoice = dataController.invoices?[indexPath.row] {
dataController.downloadInvoice(invoice) { progress, error in
// TODO: handle error
print(progress)
print(error)
if (progress < 1.0) {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath), invoiceCell = cell as? InvoiceCell, progressValue = progress {
invoiceCell.progressBar.hidden = false
invoiceCell.progressBar.progress = Float(progressValue)
invoiceCell.setNeedsDisplay()
}
}
if (progress == 1.0) {
// Here where i gonna get the downloaded file name from my model.
// invoice.filename = (Assume “2016_04_02_car_invoice_10021”)
if let filename = invoice.filename{
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docs = paths[0]
let pathURL = NSURL(fileURLWithPath: docs, isDirectory: true)
let fileURL = NSURL(fileURLWithPath: filename, isDirectory: false, relativeToURL: pathURL)
self.docController = UIDocumentInteractionController(URL: fileURL)
self.docController?.delegate = self
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) {
self.docController?.presentOptionsMenuFromRect(cell.frame, inView: self.tableView, animated: true)
if let invoiceCell = cell as? InvoiceCell {
invoiceCell.accessoryType = .Checkmark
invoiceCell.setNeedsDisplay()
}
}
}
}
}
}
}
So,my question is simple.I just don't want to use that code
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
because it use response.suggestedfilename.And I want to save file name manually on selected table view cell data.Any Help?Please don't mind that I posted some code in my question because I want everyone to see it clearly.
Destination is of type (NSURL, NSHTTPURLResponse) -> NSURL. so you can do something like this
Alamofire.download(.POST, invoice.url,parameters:params, destination: { (url, response) -> NSURL in
let pathComponent = "yourfileName"
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let fileUrl = directoryURL.URLByAppendingPathComponent(pathComponent)
return fileUrl
})
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
print(totalBytesRead)
dispatch_async(dispatch_get_main_queue()) {
let progress = Double(totalBytesRead) / Double(totalBytesExpectedToRead)
completionHandler(progress, nil)
}
}
.responseString { response in
print(response.result.error)
completionHandler(nil, response.result.error)
}
}
Swift 3.0
in swift 3.0 it's DownloadFileDestination
Alamofire.download(url, method: .get, to: { (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
return (filePathURL, [.removePreviousFile, .createIntermediateDirectories])
})
.downloadProgress(queue: utilityQueue) { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.result.value {
let image = UIImage(data: data)
}
}
for more go to the Alamofire