Cannot convert URL to Data(contentsOf: URL) in swift5 - swift

I know there are many solutions around related to converting an Image string into data and to set the image in an ImageView. But unfortunately, nothing worked in my case. I have a parsed JSON field which returns an Image as a string. So I'm trying to convert that String as URL and then to get URL data to display the image. But when the error is throwing when I try to get the data from URL like
let testImage = Data(contentsOf: forecastURL! as URL)
Error: "Incorrect argument label in call (have 'contentsOf:', expected
'dictionary:')"
if let url21 = URL(string: brandingLogo) {
do {
let testImage = Data(contentsOf: url21)
self.BrandingBarImage.image = UIImage(data: testImage)
}
catch
{
print("error")
}
}
**Code for brandingLogo:**
guard let url = URL(string: urlJson) else {return}
let task = URLSession.shared.dataTask(with: url) { (data1, response, error) in
do {
let parsedData = try JSONSerialization.jsonObject(with:data1!) as? [String:Any]
let statusList = parsedData?["data"] as? [String:Any]
let anotherData = statusList?["data"] as? [String:Any]
if let players = anotherData?["players"] as? [[String:Any]] {
for logo in players {
self.brandingLogo = logo["logo_app_branding_bar"] as? String
print(self.brandingLogo)
}
brandingLogo is parsed from Json and its value is: https://media.socastsrm.com/wordpress/wp-content/blogs.dir/223/files/2018/01/blank-300x95.png
so, I'm assuming that when this 'brandingLogo' is considered as String, it takes only the actual string like :
https://media.socastsrm.com/wordpress/wp-content/blogs.dir/223/files/2018/01/blank-300x95.png
And so I'm trying to convert that image string to URL and then to get Data
Any help is appreciated. Thank you

Related

Swift UIImageView Firebase DispatchQueue

I am using firebase to save and load my images. I have created a new view in Xcode and am using the same code I have been using to load profile images. Yet, this is now throwing an error saying that the url string is nil. The image url data disappears after "DispatchQueue.global().async". What could be causing this and how could I track this? Very strange how this code works for other views yet for this new view it is throwing an error.
let businessProfilePicture = dictionary["profPicString"] as! String
if businessProfilePicture.count > 0 {
let url = URL(string: businessProfilePicture)
print(url)
print("printing the url here to check")
DispatchQueue.global().async {
let dataURL = try? Data(contentsOf: url!)
print(dataURL)
print("printing the data url here")
DispatchQueue.main.async {
print(dataURL)
print("Printing Data to check")
let image = UIImage(data: dataURL!)?.potter_circleo
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
Full Code
func getWorkLocation() {
let uid = Auth.auth().currentUser?.uid
var profPicURL: String = ""
Database.database().reference().child("employees").child(uid!).child("Business").observe(.value, with: { snapshot in
if snapshot.exists() {
let dictionary = snapshot.value as? NSDictionary
self.businessName.text = dictionary?["businessName"] as? String
self.businessStreet.text = dictionary?["businessStreet"] as? String
self.businessCity.text = dictionary?["businessCity"] as? String
profPicURL = dictionary?["profPicString"] as! String
// set image
if profPicURL.count > 0 {
let url = URL(string: profPicURL)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
} else {
let image = UIImage(named: "profile picture")?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
self.businessName.text = ""
self.businessStreet.text = "Go to Add Work Location to send request"
self.businessCity.text = ""
self.deleteButton.isEnabled = false
}
})
}
Are you certain that the URL you create from profPicURL is being created properly?
URL(string:) can fail and return nil. If you then go on to implicitly unwrap it in Data(contentsOf: url!) you will crash.
Similarly, try? Data(contentsOf: url) can return nil. If it does, then when you implicitly unwrap it in UIImage(data: data!) you will crash.
As Jacob said in comments, you need to learn more about implicitly unwrapped optionals. To get you started, you might structure your code something like this:
if let url = URL(string: profPicURL) {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url),
let image = UIImage(data: data)?.potter_circle
{
DispatchQueue.main.async {
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}

Access a dictionary (JSON format) in a function with a flexible variable

I can't find a solution for my programming issue. I want to create a function which will access a dictionary (data is coming from the internet) an I need the following code very often:
if let job_dict = json["data"] as? [String:Any] {
It would be great to be more flexible and to change the ["data"] part to a variable or something like that:
func get_JSON(Link: String, Value: String) -> [Double] {
let url = Link
let request = URLRequest(url: URL(string: url)!)
let myUrl = URL(string: basePath)!
var ValuestoReturn = [Double]()
let task = URLSession.shared.dataTask(with: myUrl) { (data, response, error) in
if let data = data {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] {
print(Value.description)
if let job_dict = json[Value.description] as? [String:Any] {
print(job_dict)
}
}
} catch {
}
}
}
task.resume()
json[Value.description] is always wrong and the json["data"] thing is always true.
Don't use Value.Description use just Value
print(Value)
if let job_dict = json[Value] as? [String:Any] {...}
P.D: Don't use "Value" for a variable's name. The first letter in uppercase is for types. You can use value instead.

Converting Array of URLs into Array of UIImage

I have an array of URLs linking to image files, how do I store them into an array of UIImages?
var imagesArray = [UIImage]()
let links = ["http://example.com/image1.jpg","http://example.com/image2.jpg"] as [String]
There must be an easy solution.
If it was one image I could do something like the following:
let url = URL(string: link2image!)!
let imageData = try? Data(contentsOf: url)
let image = UIImage(data: imageData!)!
self.image.append(image)
The easiest solution would be to just iterate through the array and download the images synchronously using Data(contentsOf:), however, this would be quite insufficient due to synchronous execution.
let images = links.flatMap{ link->UIImage? in
guard let url = URL(string: link) else {return nil}
guard let imageData = try? Data(contentsOf: url) else {return nil}
return UIImage(data: imageData)
}
A better solution would be to download the images asynchronously in parallel, I have written a UIImage extension for this using PromiseKit:
extension UIImage {
class func downloadedAsync(fromUrl url: URL)->Promise<UIImage> {
return Promise{ fulfill, reject in
URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
guard let data = data, error == nil else {
reject(error!); return
}
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
reject(NSError(domain: "Wrong HTTP response code when downloading image asynchronously",code: (response as? HTTPURLResponse)?.statusCode ?? 1000));return
}
guard let mimeType = response?.mimeType, mimeType.hasPrefix("image"), let image = UIImage(data: data) else {
reject(NSError(domain: "No image in response", code: 700)); return
}
fulfill(image)
}).resume()
}
}
}
You call it for an array of links like this:
var imageDownloadTasks = links.flatMap{ link in
guard let url = URL(string: link) else {return nil}
return UIImage.downloadedAsync(fromUrl: url)
}
Then execute the promises:
when(fulfilled: imageDownloadTasks).then{ images in
//use the images, images is of type [UIImage]
}
Maybe you can try Functional programming use: map closure ...
links.map({
if let imageData = try? Data(contentsOf: URL(string: $0)!) {
UIImage(data: imageData)
}
})
But you must know if your links is wrong, it will crash. So, I suggest you make some guard to prevent these crashes. like this...
guard let url = URL(string: $0) else { return nil }

Displaying JSON data nicely in Swift 3

I'm quite new to swift and I'm trying to display JSON data received from a server in 3 columns, however, I'd like the text to line up and possibly remove the brackets surrounding each bit of text. I've attached an image below, along with my code.
let u = UserDefaults.standard.value(forKey: "userIP")!
var request = URLRequest(url: URL(string: "http://\(u):3000/logs")!)
request.httpMethod = "POST"
let postString = "LockID=\(lockid)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
DispatchQueue.main.async() {
self.displayMyAlertMessage("response = \(response)")
}
}
let responseString = String(data: data, encoding: .utf8)
// print("responseString = \(responseString)")
if let data = responseString?.data(using: String.Encoding.utf8) {
let resString = JSON(data: data)
if resString["success"].stringValue == "true"
{
// save the data to be manipulated and stored in table somehow
let returned_name = resString["message"].arrayValue.map({$0["name"].stringValue})
let returned_time = resString["message"].arrayValue.map({$0["lockTime"].stringValue})
let returned_type = resString["message"].arrayValue.map({$0["type"].stringValue})
DispatchQueue.main.async() {
self.updatename!.text = "\(returned_name.description)"
self.updateLock!.text = " \(returned_type.description)"
self.updateText!.text = " \(returned_time.description)"
}
}
else if resString["success"].stringValue == "false"
{
DispatchQueue.main.async() {
self.displayMyAlertMessage(resString["message"].stringValue)
}
}
Im maniplulating the JSON data with SwiftyJSON. Any ideas on how i can strip out the [""]?
Cheers
returned_name and the other returned... variables is an array of strings caused by the map function. Printing an array using the description method displays "[item1, item2, item3]". To print each string separately you need a repeat loop.
let returnedArray = resString["message"].arrayValue // you might cast the object to `[[String:Any]]`
for item in returnedArray {
print(item["name"])
print(item["lockTime"])
print(item["type"])
}
To display the values in a table view you need a model, the best way is a custom struct
struct Item {
let name : String
let lockTime : String
let type : String
}
Then create a data source array
var items : [Item]()
And map your received JSON to the model
let returnedArray = resString["message"].arrayValue
for item in returnedArray {
let name = item["name"] ?? ""
let lockTime = item["lockTime"] ?? ""
let type = item["type"] ?? ""
items.append(Item(name:name, lockTime:lockTime, type:type))
}
Put the code to parse the JSON in viewDidLoad and call reloadData() at the end, in cellForRow get the item for the row from the array and display the values for example:
let item = items[indexPath.row]
self.updatename!.text = item.name
self.updateLock!.text = item.lockTime
self.updateText!.text = item.type
PS: since you are new to Swift don't use snake case variable names (returned_name), use camel case (returnedName).

how to save image to database table through web api in swift

I am building an app using Swift 3.0 for study purpose.
One of the functions is to fetch and save data from(to) SQL Server database tables. One of the columns is to store IMAGE(photo) in table: data type in table is Image (system.Byte[]) in SQL Server.
I can get the photo column through web api and show it in Image component like this:
let encodedImageData = My web api url
let imageData = NSData(base64EncodedString: encodedImageData options: .allZeros)
let image = UIImage(data: imageData)
let imageView.image = image
I had problem to save the Image to the database through web api (can save other columns, but had problem with Image column).
I tried this:
let data = UIImagePNGRepresentation(image) as NSData?
but failed.
my web api and invoke as below:
func post(parameters : Dictionary<String, String>, urlString : String) {
var request = URLRequest(url: URL(string: urlString)!)
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters)
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error: \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: .utf8) // No error thrown, but not dictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: .utf8)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
}
#IBAction func insert(){
let imageData = UIImagePNGRepresentation(myimageview.image!) as NSData?
post(parameters: ["Name": nametxt.text!,"Address": addresstxt.text!,"photoname": photonametxt.text!,"photo": String(describing: imageData),"url": urltxt.text! ], urlString: "http://XXXXXXX/api/myfavorites")
}
Can someone help me have a look at image save method to database table in Swift?
I think you are using the wrong data structure for your image. Instead of using NSData and String(describing:) (which definitely does not do what you want), you should directly use a base64 encoded string, like the following code:
#IBAction func insert(){
let imageBase64String = UIImagePNGRepresentation(myimageview.image!)?.base64EncodedString()
post(parameters: ["Name": nametxt.text!,"Address": addresstxt.text!,"photoname": photonametxt.text!,"photo": imageBase64String,"url": urltxt.text! ], urlString: "http://XXXXXXX/api/myfavorites")
}