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.
Related
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)
}
}
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()
I'm trying to make the conversion from Objc to swift and have had better days.
I have a class with a dictionary:
collaborationDictionary:[String:Set<String>]
I am trying to write/read this dictionary to/from a file and just can't quite seem to make it work. I have to save the dictionary using the following JSON structure and I have to use SwiftyJSON.
{ "Collaborations" : {
"5604" : [
"whiteboard.png",
"VID_20161123_135117.3gp",
"Photo_0.jpeg"]
"5603" : [
"VID_20161123_135117.3gp"],
"5537" : [
"Screenshot_20151212-132454.png",
"VID_20161202_083205.3gp",
"VID_20161123_135117.3gp",
"Photo_0.jpeg",
"Screenshot_20151212-132428.png",
"Screenshot_20151212-132520.png",
"IMG_20161017_132105.jpg",
"whiteboard.png"]}
}
I don't have any real problem with finding/retrieving the file or writing the file. I just can't quite figure out how to manually load SwiftyJSON. I need to have a JSON object called "Collaborations" at the top. It needs to contain a dictionary of collaboration IDs (5604, 5603...). Each collaboration contains an array of string (filenames). I'm including the code I'm using to read/write the file but I need help with the SwiftyJSON library.
This is the member data member I'm using to store the above data:
These are the functions I need to finish:
private var collaborationDictionary:[String:Set<String>] = [:]
func getUploadedFileSet() {
collaborationDictionary = [:]
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
do {
let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
let json = JSON(data: data)
// ************************************************
// NEED HELP START
// NOW WHAT???? What is the SwiftyJSON code
?????????????????????????
// NEED HELP END
// ************************************************
} catch let error {
print(error.localizedDescription)
}
}
}
func saveUploadedFilesSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
do {
let dirExists = FileManager.default.fileExists(atPath: (appURL?.absoluteString)!)
if !dirExists {
try FileManager.default.createDirectory(atPath: (appURL?.absoluteString)!, withIntermediateDirectories: false, attributes: nil)
}
// ************************************************
// NEED HELP START
// NOW WHAT???? What is the SwiftyJSON code
?????????????????????????
// NEED HELP END
// ************************************************
// Write to file code - haven't written it yet but that should be easy
} catch let error as NSError {
print(error.localizedDescription);
}
}
Any direction would be greatly appreciated. Thanks!
EDIT
I was able to figure out how to load the supplied JSON structure from file. Here is the code:
func getUploadedFileSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
do {
let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
let json = JSON(data: data)
if json != nil {
for (key, subJson) in json[kCollaborations] {
let stringArray:[String] = subJson.arrayValue.map { $0.string! }
let stringSet = Set(stringArray)
collaborationDictionary.updateValue(stringSet, forKey: key)
}
} else {
print("Could not get json from file, make sure that file contains valid json.")
}
} catch let error {
print(error.localizedDescription)
}
}
I still haven't figured out how to save the collaborationDictionary object to file. My biggest problem is figuring out how to put in the "Collaborations" key. Any ideas?
I finally got this to work. The biggest problem was that I couldn't convert collaborationDictionary to JSON. I finally had to convert it to a dictionary of arrays vs dictionary of sets. Here are the 2 methods:
// **************************************************************************
func getUploadedFileSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
do {
let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
let json = JSON(data: data)
if json != nil {
for (key, subJson) in json[kCollaborations] {
let stringArray:[String] = subJson.arrayValue.map { $0.string! }
let stringSet = Set(stringArray)
collaborationDictionary.updateValue(stringSet, forKey: key)
}
} else {
print("Could not get json from file, make sure that file contains valid json.")
}
} catch let error {
print(error.localizedDescription)
}
}
}
// **************************************************************************
func saveUploadedFilesSet() {
let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
let adjustedJSONFileURL = URL(fileURLWithPath:(jsonFileURL?.absoluteString)!)
do {
let dirExists = FileManager.default.fileExists(atPath: (appURL?.absoluteString)!)
if !dirExists {
try FileManager.default.createDirectory(atPath: (appURL?.absoluteString)!, withIntermediateDirectories: false, attributes: nil)
}
// Convert set elements to arrays
var convertedCollaborationDictionary: [String:[String]] = [:]
for (sessionID, fileNameSet) in collaborationDictionary {
let array = Array(fileNameSet)
convertedCollaborationDictionary.updateValue(array, forKey: sessionID)
}
let json: JSON = JSON(convertedCollaborationDictionary)
let fullJSON: JSON = [kCollaborations:json.object]
let data = try fullJSON.rawData()
try data.write(to: adjustedJSONFileURL, options: .atomic)
} catch let error as NSError {
print(error.localizedDescription);
}
}
If you dig into the source, SwiftyJSON wraps JSONSerialization, which can both be initialized and converted back to Data which is knows how to read and write itself from disk:
func readJSON() -> JSON? {
guard let url = Bundle.main.url(forResource: "data", withExtension: "json"),
let data = try? Data(contentsOf: url) else {
return nil
}
return JSON(data: data)
}
func write(json: JSON, to url: URL) throws {
let data = try json.rawData()
try data.write(to: url)
}
Note that you can load your static data from anywhere including your Bundle, but you can only write to the sandbox (ie the Documents directory). You may wish to copy from your Bundle to the documents directory on first run if you are planning on reading/writing to the same file.
Also your sample JSON is bad (lint it). You need a comma after "Photo_0.jpeg"]
I have the following Swift extension on NSURL
public extension NSURL {
func getQueryItemValueForKey(key: String) -> String? {
guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false) else {
return nil
}
guard let queryItems = components.queryItems else { return nil }
return queryItems.filter {
$0.name == key
}.first?.value
}
}
I am writing unit tests for it but I am unable to get 100% code coverage as I don't seem to be able to get NSURLComponents(URL: self, resolvingAgainstBaseURL: false) to return nil. From what I understand, this requires a malformed URL but I am struggling to create one.
I have tried:
let url = NSURL(string: "")
let url = NSURL(string: "http://www.example")
let url = NSURL(string: "http://www.exam ple.com")
let url = NSURL(string: "http://www.example.com/?param1=äëīòú")
And some others that I lost track of. I know this is probably something blatantly obvious but i'm lost at the moment. So, how do I create a malformed URL in Swift?
As found in my research, you can produce a url that is malformed for NSURLComponents but not for NSURL by using negative port number (probably there are more cases but not sure):
let example = "http://example.com:-80/"
let url = NSURL(string: example)
print("url:\(url)") //prints out url:Optional(http://example.com:-80/)
if let url = url {
let comps = NSURLComponents(URL: url, resolvingAgainstBaseURL: false)
print("comps:\(comps)") //prints out comps:nil
}
let imgURL:NSURL = NSURL(string: "\(ImageName)")!
at the above line,i'm getting fatal error
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Code :
let ImageName = obj["image"] as! String
let imgURL:NSURL = NSURL(string: "\(ImageName)")!
let request: NSURLRequest = NSURLRequest(URL: imgURL)
let session = NSURLSession.sharedSession()
let Imgtask = session.dataTaskWithRequest(request){
(data, response, error) -> Void in
if (error == nil && data != nil)
{
func display_image()
{
pointAnnoation.DisplayImage = UIImage(data: data!)
}
dispatch_async(dispatch_get_main_queue(), display_image)
}
}
Imgtask.resume()
From the above code im trying to store my image from database in annotation
if i printed the 'ImageName' it returns the name from the database correctly, but unable to retain the image
it resulting in the error while running.
You say that
if i printed the 'ImageName' it returns the name from the database correctly
Then that must mean that the ImageName is not valid for a URL
If you look at the description of NSURL(string:) it says:
The URL string with which to initialize the NSURL object. This URL string must conform to URL format as described in RFC 2396, and must not be nil. This method parses URLString according to RFCs 1738 and 1808.
So the question is...how does ImageName look? And can you create a URL from it?
Apart from that, it is always a good idea to use ? instead of ! as #PhillipMills says
Update: I can see that you have posted an example of your URL now. If I do this in a playground:
let url = NSURL(string: " goo.gl/pBmA0d")
I get nil in return, so it would seem that short URLs and NSURLaren't the best of friends.
Update 2: hmm, guess I spoke to quickly, if you look at the above you can see that I have a space before the goo.gl part, if I change that to:
let url = NSURL(string: "goo.gl/pBmA0d")
it actually works, I get a NSURL object.
But another thing I stumbled upon in your code. You declare ImageName as a String here:
let ImageName = obj["image"] as! String
So you don't have to wrap it in \() later on
let imgURL:NSURL = NSURL(string: "\(ImageName)")!
You could simply say:
let imageURL = NSURL(string: ImageName)
And then...as others has said, it is always a good idea to use ? instead of !
So you could write:
if let imageName = obj["image"] as? String,
let imageURL = NSURL(string: imageName) {
//we're in business :-)
}
and be safe and sound
Try to use guard or if let for helping yourself.
let ImageName = obj["image"] as! String
if let imgURL = NSURL(string: ImageName) {
let request: NSURLRequest = NSURLRequest(URL: imgURL)
let session = NSURLSession.sharedSession()
let Imgtask = session.dataTaskWithRequest(request){ (data, response, error) -> Void in
if (error == nil && data != nil)
{
// What's that func??
func display_image()
{
pointAnnoation.DisplayImage = UIImage(data: data!)
}
dispatch_async(dispatch_get_main_queue(), display_image)
}
}
}
Imgtask.resume()
Don't make force unwrap...use if let to avoid crash ...
if let img = obj["image"] as? String,
imgURL = NSURL(string: img) {
// ... continue with your code ...
}
Please try the following code:
//ImageName is a String type.
guard let ImageName = obj["image"] as? String , let imgURL = NSURL(string: ImageName) else{
return
}
let request: NSURLRequest = NSURLRequest(URL:imgURL)
let session = NSURLSession.sharedSession()
let Imgtask = session.dataTaskWithRequest(request){
(data, response, error) -> Void in
if (error == nil && data != nil)
{
func display_image()
{
pointAnnoation.DisplayImage = UIImage(data: data!)
}
dispatch_async(dispatch_get_main_queue(), display_image)
}
Imgtask.resume()