NSURL to NSDATA or Data is always nil - ios

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
}

Related

UNNotificationAttachment set image URL to Caches directory

I have Image cache mechanism in my app. I also need to show local notifications with images. I have a problem. When I try to set UNNotificationAttachment with an image, I get an image from my cache or, if an image doesn't exist, I download it and cache. Then I build a URL to Caches directory, but when I pass this URL to UNNotificationAttachment, I get an error: NSLocalizedDescription=Invalid attachment file URL. What do I make wrong?
if let diskUrlString = UIImageView.sharedImageCache.diskUrlForImageUrl(imageUrl) {
if let diskUrl = URL(string: diskUrlString) {
do {
res = try UNNotificationAttachment(identifier: imageUrlString, url: diskUrl, options: nil)
} catch (let error) {
print("error", error)
// Invalid attachment file URL
}
}
}
func diskUrlForImageUrl(_ imageUrl: URL) -> String? {
let urlRequest = URLRequest(url: imageUrl)
return ImageCache.cacheDirectory.appending("/\(ImageCache.imageCacheKeyFromURLRequest(urlRequest))")
}
static fileprivate var cacheDirectory: String = { () -> String in
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
let res = documentsDirectory.appending("/scAvatars")
let isExist = FileManager.default.fileExists(atPath: res, isDirectory: nil)
if !isExist {
try? FileManager.default.createDirectory(atPath: res, withIntermediateDirectories: true, attributes: nil)
}
return res
}()
I have found that if I add a prefix file:///private to diskUrlString, then URL builds like expected. But I didn't still understand, how to build the url without hardcoding this prefix. So now I can use both cache and UNNotificationAttachment!
The problem here is that you are using a path, not a URL. A path is a string, like "/var/log/foo.log". A URL is semantically more complex than a path. You need a URL that describes the location of the image file on the device file system.
Build a properly constructed URL to the image file and the attachment may work. The attachment may also need a type identifier hint to tell iOS what kind of data is in the file.
You do not have to use urls. You can use image data with UNNotificationAttachment.
Here is a sample code.
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
let imageURL = URL(fileURLWithPath: paths.first!).appendingPathComponent("\(fileName).jpg")
let image = UIImage(contentsOfFile: imageURL.path)
let imageData = image?.pngData()
if let unwrappedImageData = imageData, let attachement = try? UNNotificationAttachment(data: unwrappedImageData, options: nil) {
content.attachments = [attachement]
}

Load CKAsset into UIWebView

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)
}
}

Different action by prefix of URL

Here is my situation: i'm calling file locally on my ios application ( Running in Swift).
If the file is a jpg, one action happen, if the file is a mp4, another action happen.
For this i'musing this code:
let urlString = "\(posts[selectedIndexPath].link)"
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileName = urlString as NSString;
let filePath="\(documentsPath)/\(fileName.lastPathComponent)";
let fileURL = NSURL.init(fileURLWithPath: filePath)
let request = NSURLRequest.init(url: fileURL as URL)
/* END DOWNLOAD + READ LOCALY */
if (fileURL.pathExtension?.hasPrefix("jpg"))! {
Swift.print("THIS IS A JPG")
}
else if (fileURL.pathExtension == "mp4") {
Swift.print("THIS IS A MP4")
}
This works perfectly.
What i need to do now is instead of calling th eifle locally, to calling it form an URL.
I read my file from an url by:
videoVRView.load(from: URL(string: "\(posts[selectedIndexPath].link)")
Which work.
But from that, the action is not working, i've try the following:
if ((from: URL(string: "\(posts[selectedIndexPath].link)").hasPrefix("jpg"))! {
Swift.print("THIS IS A JPG")
}
else if ((from: URL(string: "\(posts[selectedIndexPath].link)") == "mp4") {
Swift.print("THIS IS A MP4")
}
Without any success !!
Does anybody know how is this achievable ?
Thanks a lot =)
-- EDIT --
What im trying to do is th efollowing to resume:
at th emoment i call image locally via:
imageVRView.load(UIImage(named: "\(documentsPath)/\(fileName.lastPathComponent)" ),
of: GVRPanoramaImageType.stereoOverUnder)
I try instead to use:
imageVRView.load(UIImage(named: "\(posts[selectedIndexPath].link)" ),
of: GVRPanoramaImageType.stereoOverUnder)
Without success . . . . I need to call the image via this method ... any idea ?
Thanks a lot !
You can make a URL request for the url header using the httpMethod HEAD to check your url mime type without the need to download the data first:
let link = "https://www.dropbox.com/s/sk46eyglvijlrec/horse.jpg?dl=1"
let url = URL(string: link)!
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
URLSession.shared.dataTask(with: request) { _ , response , _ in
guard let response = response, (response as? HTTPURLResponse)?.statusCode == 200 else { return }
DispatchQueue.main.async() {
print("mimeType", response.mimeType ?? "nil") // image/jpeg
print("suggestedFilename:", response.suggestedFilename ?? "no suggestedFilename") // horse.jpg
print("expectedContentLength:", response.expectedContentLength ?? "nil") // 352614
print("textEncodingName:", response.textEncodingName ?? "nil")
print("url:", response.url ?? "nil") // "https://dl.dropboxusercontent.com/content_link/RNrhGtvroTLU1Gww7eQo1N1ePRiix68zsqZJ1xWPjKm3pmOUNQwNVntbPuFG4jZ8/file?dl=1"
}
}.resume()

Fatal error Xcode 8 Swift 3

ok guys can I get a little help with my code. When running the app I get an error is there any way to fix this problem?
let fileUrl = dict["fileUrl"]as! String
let url = NSURL(string: fileUrl)
let data = NSData(contentsOf: url! as URL!)
let picture = UIImage(data: data! as Data!)
let photo = JSQPhotoMediaItem(image: picture)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: photo))
Image here
Here I see 4 big fat problems with your code.
You are force casting the value of fileUrl of the dictionary dict to String. If your dictionary doesn't have the value for fileUrl, or if it's not castable to string, your code will crash. You should change that to optional cast like:
if let fileUrl = dict["fileUrl"] as? String
{
//your code if you have fileUrl
}
When creating the url to the file, you are using the wrong initialization method, you should be using this:
let url = URL(fileURLWithPath: fileUrl)
After you have the url to the file, you should also check if you have the data of the file, because contentsOfFile: initializer of the NSData returns the optional object, which may be nil, so another if check:
if let data = NSData(contentsOf: url) {\\ code with the data}
init?(data: Data) initializer of the UIImage also returns optional object, so if the required by latter code, you should also check if you have the image or nil with if statement.
The result code should be something like:
if let fileUrl = dict["fileUrl"] as? String {
let url = URL(fileURLWithPath: fileUrl)
if let data = NSData(contentsOf: url) {
let image = UIImage(data: data as Data) // you can cast NSData to Data without force or optional casting
let photo = JSQPhotoMediaItem(image: image)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: photo))
}
}
Hope this helps.
Replace the first line of code with this line for optional binding check :-
guard let fileUrl = dict["fileUrl"] as! String else {return}
Yo should do validation in cases where the variable may be nil, the following is an example:
if let fileUrl = dict["fileUrl"] as? String {
let url = URL(string: fileUrl)
do {
let data = try Data(contentsOf: url!)
let picture = UIImage(data: data)
let photo = JSQPhotoMediaItem(image: picture)
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName, media: photo))
} catch {
}
}

From raw data to UIImagePNGRepresentation in fewer steps

Using this code, I extract an image from a Share Extension and I write it to a directory I created in an App Group.
let content = self.extensionContext!.inputItems[0] as! NSExtensionItem
let contentType = kUTTypeImage as String
for attachment in content.attachments as! [NSItemProvider] {
if attachment.hasItemConformingToTypeIdentifier(contentType) {
attachment.loadItem(forTypeIdentifier: contentType, options: nil) { data, error in
// from here
if error == nil {
let url = data as! NSURL
let originalFileName = url.lastPathComponent
if let imageData = NSData(contentsOf: url as URL) {
let img = UIImage(data:imageData as Data)
if let data = UIImagePNGRepresentation(img!) {
// write, etc.
}
}
}
}
Anything is working fine.
What I'd like to know is if it is possible to reduce some code: in particular, after if error == nil, I:
cast data to NSURL;
use NSURL to get a NSData;
use NSData to get a UIImage;
use UIImage to get a UIImagePNGRepresentation;
Aside from avoiding the creation of the imageData variable, isn't there a way to (safely) achieve the same goal with fewer steps?
First of all you need to use native Data and URL instead of NSData & NSURL also if you want to write file in DocumentDirectory then you can directly use that imageData no need to make UIImage object from it and then convert it to data using UIImagePNGRepresentation.
if let url = data as? URL, error == nil {
let originalFileName = url.lastPathComponent
if let imageData = try? Data(contentsOf: data) {
// write, etc.
var destinationURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
destinationURL.appendPathComponent("fileName.png")
try? imageData.write(to: destinationURL)
}
}

Resources