I am trying to load a PDF File stored in a publicDatabase as a CKAsset, the code worked well on an existing application, published last year. However I now get the following error
Cannot convert value of type 'NSData' to type 'Data' in coercion
here is the code -
if docType == "PDF" || docType == "pdf" {
if let asset1 = record.object(forKey: "documentFile") as? CKAsset {
let doc1Data : NSData? = NSData(contentsOf:asset1.fileURL)
let path = (NSTemporaryDirectory() as NSString).appendingPathComponent(filename)
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)
do {
try doc1Data!.write(to: URL(fileURLWithPath: path), options: .atomic)
} catch {
print(error)
}
self.docWebView.load(doc1Data! as Data, mimeType: "application/pdf", textEncodingName: "UTF-8", baseURL: NSURL() as URL)
self.filenameURL = [(fileURL)]
}
I'm sure there must be a simple explanation, but I cannot see the problem
Thanks in Advance.
Try changing the below line :
let doc1Data : NSData? = NSData(contentsOf:asset1.fileURL)
to
let doc1Data = NSData(contentsOf:asset1.fileURL)
It would appear the answer is simple, change the load Data to loadRequest and reference the URL of the document having obtained it from the CKAsset
if docType == "PDF" || docType == "pdf" {
if let asset1 = record.object(forKey: "documentFile") as? CKAsset {
let doc1Data : NSData! = NSData(contentsOf:asset1.fileURL)
let path = (NSTemporaryDirectory() as NSString).appendingPathComponent(filename)
do {
try doc1Data!.write(to: URL(fileURLWithPath: path), options: .atomic)
let url = URL(fileURLWithPath: path)
let urlRequest = URLRequest(url: url)
self.docWebView?.loadRequest(urlRequest)
} catch {
print(error)
}
}
Related
data coming from server is in ex.2035bytes I want to write this data in to file I am writing but data is not showing
Alamofire.request(url , method: .post, parameters: Parameters as? [String: Any] , encoding: URLEncoding.httpBody, headers: [
"Content-Type": "application/x-www-form-urlencoded"
]).responseData{ (response) in
print(response)
print(response.result.value!)
print(response.result.description)
guard let jsonData = response.result.value ,response.result.isSuccess else {
didFail(response.result.error!)
return
}
guard let id = ApplicantModel.shared.applicationId else {
return
}
let file = "application_\(id)" //this is the file. we will write to and read from it
let documentsPath1 = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
//let logsPath = documentsPath1.appendingPathComponent("f")
let fileURL = documentsPath1.appendingPathComponent("file")
let data: Data = response.result.value!
// print(logsPath)
//writing
do {
try FileManager.default.createDirectory(at: documentsPath1 as URL, withIntermediateDirectories: true, attributes: nil)
//try data.write(to: fileURL!, atomically: false, encoding: .utf8)
// try data.write(to: fileURL!, options: Data.WritingOptions.atomic)
try data.write(to: fileURL!) )
}
catch {/* error handling here */}
let json = JSON(jsonData)
didFinish(json)
}
here I am creating file and writing data in to it but its not showing
You can use this function to write data. Code is self explanatory, but I tried to make it more clear.
func writeToFile(data: Data, fileName: String){
// get path of directory
guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
return
}
// create file url
let fileurl = directory.appendingPathComponent("\(fileName).txt")
// if file exists then write data
if FileManager.default.fileExists(atPath: fileurl.path) {
if let fileHandle = FileHandle(forWritingAtPath: fileurl.path) {
// seekToEndOfFile, writes data at the last of file(appends not override)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
else {
print("Can't open file to write.")
}
}
else {
// if file does not exist write data for the first time
do{
try data.write(to: fileurl, options: .atomic)
}catch {
print("Unable to write in new file.")
}
}
}
You have a problem with creating the directory and naming the file you need to change it like this
let file = "application_\(id)"
let documentsPath1 = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let logsPath = documentsPath1.appendingPathComponent("file")
do
{
try FileManager.default.createDirectory(atPath: logsPath!.path, withIntermediateDirectories: true, attributes: nil)
let fileURL = logsPath?.appendingPathComponent(file)
try data.write(to: fileURL!)
}
catch let error as NSError
{
NSLog("Unable to create directory \(error.debugDescription)")
}
I think you create a wrong folder. It due to you can't save that file in your folder. You can look at my example. Which I create 1 folder to contain files.
Step1: Get document path
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
Step2: create a destination URL. Where you would like to store
let url = paths[0].appendingPathComponent(self.fileImagejpeg)
Step 3: Write data in files
try? data.write(to: url)
You can use try catch to get log when write failure
I have a query on a Cloud CKRecord, which checks to see if a documents exists (i.e. has been uploaded as an CKAsset) and if not checks if a URL exists (i.e. has been uploaded as a String). All works well if either exist on their own for a given record, however if both exist when clicking on the link nothing happens.
I feel it is something to do with the if and else if statements -
if filename1 != nil {
let asset1 = record.object(forKey: "courseDocument1") as? CKAsset
let filename = record.object(forKey: "courseDocument1Filename") as! String
let path = (NSTemporaryDirectory() as NSString).appendingPathComponent(filename)
let doc1Data : NSData? = NSData(contentsOf:(asset1?.fileURL)!)
do {
try doc1Data!.write(to: URL(fileURLWithPath: path), options: .atomic)
let url = URL(fileURLWithPath: path)
let urlRequest = URLRequest(url: url)
self.courseDoc1WebView?.loadRequest(urlRequest)
self.venueDocButton1.setTitle(cseDocument1,for: [])
self.venueDocButton1.isHidden = false
self.courseDocumentLabel.isHidden = false
} catch {
print(error)
}
} else if cseDocument1URL != nil && filename1 == nil {
let url1 = URL (string: cseDocument1URL!)
let request1 = URLRequest(url: url1! as URL );
self.courseDoc2WebView.loadRequest(request1 as URLRequest);
self.venueDocButton1.setTitle(cseDocument1,for: [])
self.venueDocButton1.isHidden = false
self.courseDocumentLabel.isHidden = false
} else {
print("No Document Found")
}
Any thoughts?
This turned out to be a simple typo rather than logic -
self.courseDoc2WebView.loadRequest(request1 as URLRequest);
which should actually be -
self.courseDoc1WebView.loadRequest(request1 as URLRequest);
This was solved by printing responses and using the debugger - thanks Phillip Mills
Duncan C, you make a good point too - thank-you.
I'm trying to save both a recorded video's file path, and a thumbnail from the video to the documents directory. Then, set those two values to an object using the file paths so I can use the object to populate a collection view. With the code I have currently (below), after I record a video, the video path gets saved to the documents directory, and the video path and thumbnail get set to my Post object, and the thumbnail appears properly in my collection view. All good so far.
However only the video path persists between app re-launches since it's in the directory, and the thumbnail isn't. I'd like to save the thumbnail there too but I don't know how to go about it since it appears you can only write URLs to the directory.
This is my first experience with utilizing the documents directory so any help will be appreciated! How can I write the thumbnail (UIImage) to my documents directory along with the video it's from?
Here's my code so far:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
dismiss(animated: true, completion: nil)
if mediaType == kUTTypeMovie {
// Componenets for a unique ID for the video
var uniqueVideoID = ""
var videoURL:NSURL? = NSURL()
var uniqueID = ""
uniqueID = NSUUID().uuidString
// Get the path as URL
videoURL = info[UIImagePickerControllerMediaURL] as? URL as NSURL?
let myVideoVarData = try! Data(contentsOf: videoURL! as URL)
// Write the video to the Document Directory at myVideoVarData (and set the video's unique ID)
let docPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentsDirectory: AnyObject = docPaths[0] as AnyObject
uniqueVideoID = uniqueID + "VIDEO.MOV"
let docDataPath = documentsDirectory.appendingPathComponent(uniqueVideoID) as String
try? myVideoVarData.write(to: URL(fileURLWithPath: docDataPath), options: [])
print("docDataPath under picker ", docDataPath)
print("Video saved to documents directory")
// Create a thumbnail image from the video (first frame)
let asset = AVAsset(url: URL(fileURLWithPath: docDataPath))
let assetImageGenerate = AVAssetImageGenerator(asset: asset)
assetImageGenerate.appliesPreferredTrackTransform = true
let time = CMTimeMake(asset.duration.value / 3, asset.duration.timescale)
if let videoImage = try? assetImageGenerate.copyCGImage(at: time, actualTime: nil) {
// Add thumbnail & video path to Post object
let video = Post(pathToVideo: URL(fileURLWithPath: docDataPath), thumbnail: UIImage(cgImage: videoImage))
posts.append(video)
print("Video saved to Post object")
}
}
}
One Suggestion: Save images to Library/Caches if that can be downloaded again as per apple's guide line.
As simple as this:
func saveImageToDocumentDirectory(_ chosenImage: UIImage) -> String {
let directoryPath = NSHomeDirectory().appending("/Documents/")
if !FileManager.default.fileExists(atPath: directoryPath) {
do {
try FileManager.default.createDirectory(at: NSURL.fileURL(withPath: directoryPath), withIntermediateDirectories: true, attributes: nil)
} catch {
print(error)
}
}
let filename = NSDate().string(withDateFormatter: yyyytoss).appending(".jpg")
let filepath = directoryPath.appending(filename)
let url = NSURL.fileURL(withPath: filepath)
do {
try UIImageJPEGRepresentation(chosenImage, 1.0)?.write(to: url, options: .atomic)
return String.init("/Documents/\(filename)")
} catch {
print(error)
print("file cant not be save at path \(filepath), with error : \(error)");
return filepath
}
}
Swift4:
func saveImageToDocumentDirectory(_ chosenImage: UIImage) -> String {
let directoryPath = NSHomeDirectory().appending("/Documents/")
if !FileManager.default.fileExists(atPath: directoryPath) {
do {
try FileManager.default.createDirectory(at: NSURL.fileURL(withPath: directoryPath), withIntermediateDirectories: true, attributes: nil)
} catch {
print(error)
}
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMddhhmmss"
let filename = dateFormatter.string(from: Date()).appending(".jpg")
let filepath = directoryPath.appending(filename)
let url = NSURL.fileURL(withPath: filepath)
do {
try chosenImage.jpegData(compressionQuality: 1.0)?.write(to: url, options: .atomic)
return String.init("/Documents/\(filename)")
} catch {
print(error)
print("file cant not be save at path \(filepath), with error : \(error)");
return filepath
}
}
I am a little lost on my quest to -
Download a CKAsset (PDF File)
Assign a Temporary Filename
Write the contents of the CKAsset to the filename
I have managed to download the CKAsset and display the contents in a UIWebView, however I am stumbling over steps 2 and 3, I have a filename from a String, and despite trying a variety of WriteToFile combinations I receive errors.
My code is thus :
let filename = record.object(forKey: "materialsFilename")
if materialsType == "PDF" || materialsType == "pdf" {
if let asset1 = record.object(forKey: "materialsFile") as? CKAsset {
let doc1Data : NSData? = NSData(contentsOf:asset1.fileURL)
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename as! String)
let contentsOfFile = doc1Data
var error: NSError?
// Write File
if contentsOfFile.writeToFile(path, atomically: true, encoding: String.Encoding.utf8, error: &error) == false {
if let errorMessage = error {
print("Failed to create file")
print("\(errorMessage)")
}
} else {
print("File \(filename) created at tmp directory")
}
This version presents the error -
Cannot invoke 'writeToFile' with an argument list of type '(URL?,
atomically: Bool, encoding: String.Encoding, error: inout NSError?)'
The temporary file once created will be passed to a UIActivityViewController, to print / email / airdrop the PDF, having only a CKAsset name, the the UIActivityViewController cannot associate the file type to any of the users installed apps, save for print.
After a little head scratching and reviewing my choices following the pointers above, I changed tack and didn't really need to write to a file, just rename the CKAsset, which I achieved with the following script -
let materialsType = record.object(forKey: "materialsType") as! String
let filename = record.object(forKey: "materialsFilename") as! String
if materialsType == "PDF" || materialsType == "pdf" {
if let asset1 = record.object(forKey: "materialsFile") as? CKAsset {
let doc1Data : Data? = Data(contentsOf:asset1.fileURL) as Data?
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)
self.materialsWebView.load(doc1Data! as Data, mimeType: "application/pdf", textEncodingName: "UTF-8", baseURL: NSURL() as URL)
self.filenameURL = [(fileURL)]
}
The key seemed to hinge on two lines -
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)
and
self.filenameURL = [(fileURL)]
Which generates the filename for the UIActivityViewController and thus opens up the access to a number of additional Apps.
Are you sure you're using the correct writeToFile method? The NSData reference doesn't show a method with the same signature you're using. Try using one of the ones listed in the reference.
I only find the following function in Data class.
func write(to: URL, options: Data.WritingOptions)
Try this.
I am trying to upload a video to a server file through Alamofire but I couldn't get the "data" going to be passed..its always nil
var videoURL = NSURL(string: "")
//returns Optional(file:///private/var/mobile/Containers/Data/Application/1FB40086-228B-4011-A9D4-7874E2EEF9F4/tmp/4A6AAD76-B899-4B67-8E96-925DA4AE9E93.mov)
let videodata = NSData(contentsOfFile: (videoURL?.absoluteString)!)
//nil
let url = NSURL(fileURLWithPath: (videoURL?.absoluteString)!)
let videodata = NSData(contentsOf: url as URL)
//nil
If I get data would lead a way for me to do this:
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append (videodata as! Data, withName: "file", fileName: "file.mov", mimeType: "video/quicktime")
enter code here
EDIT::
thank you guys, with your help I have struggled my way out of there to this file not found error, but I can see the file is being saved in my gallery, any clue would save my day.
print (videoURL!)
//returns file:///private/var/mobile/Containers/Data/Application/3F280477-DA16-4A67-AE60-D6247143352E/tmp/1E4AC002-6AD0-41E1-9E0D-A09B697F81F7.mov
print (videoURL!.path!)
// returns /private/var/mobile/Containers/Data/Application/3F280477-DA16-4A67-AE60-D6247143352E/tmp/1E4AC002-6AD0-41E1-9E0D-A09B697F81F7.mov
var videoData = NSData()
let path = videoURL!.path!
if FileManager.default.fileExists(atPath: path) {
}else {
print("Could not fin file at url: \(videoURL!.path!)")
// here it throws file not found
}
In Swift 3 use native URL and Data instead of NSURL and NSData.
if let videoURL = URL(string: urlString), let videodata = try? Data(contentsOf: videoURL) {
//Add code of Alamofire here
}
Using absoluteString returns a string that includes file:// at the beginning and you don't want that. You need to return the path of the URL
guard let videoPathString = videoURL.path as? String else {
//handle error here if you can't create a path string
return
}
var videoData = NSData()
//check if file exists at this path first
if (NSFileManager.defaultManager().fileExistsAtPath(videoPathString)) {
videoData = NSData(contentsOfFile: NSString(videoPathString))
} else {
//if file does not exist at that path, handle here
}