Getting API Data within Swift - json

I'm trying to get some data from an API at the address https://api.coinmarketcap.com/v1/ticker/bitcoin/?convert=AUD
I've started a new playground within Xcode, and my code is as follows
let urlString = "https://api.coinmarketcap.com/v1/ticker/bitcoin/?convert=AUD"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error as Any)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let id = parsedData["id"] as! [String:Any]
print(id)
} catch let error as NSError {
print(error)
}
}
}.resume()
However the playground is returning no result. I am quite new to Swift, so some of the syntax may be a little off. Can anyone make a suggestion how to obtain the information obtained at the API address?
Thanks!

You need to import PlaygroundSupport and set needsIndefiniteExecution to true.
Also you have some errors in the code as the result is array and you are casting it into a dictionary [String : Any].
Use the following code:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let urlString = "https://api.coinmarketcap.com/v1/ticker/bitcoin/?convert=AUD"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as! [[String : Any]]
for item in parsedData
{
let id = item["id"] as! String
print(id)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}.resume()

Related

How to extract value from JSON object with dictionary [Swift 4]

I'm trying to make an async API get request to openweathermap.org 's API. The result should be this JSON structure. I'm particularly trying to get the temperature. I was taught to work with it by wrapping the JSON to a dictionary. Thing is I don't know what I can use to specify the object "main" (in the JSON) and get the temperature. Do I have to iterate object by object? This is my code so far (side note: is it worrying that my app uses 50 mb of RAM?)
let url = URL(string: stringURL)
let myQ = DispatchQueue.init(label: "getCityDetails")
myQ.async {
let session = URLSession.shared
let m = session.dataTask(with: url!, completionHandler: {(data, response, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Error with the response, unexpected status code: \(String(describing: response))")
return
}
do {
if let d = data{
let dictionaryObj = try JSONSerialization.jsonObject(with: d, options: []) as! NSDictionary
print(dictionaryObj)
}
}catch{
print(error.localizedDescription)
}
})
m.resume()
The first point is that the default URLSession works in a background thread so you dont need to create a dispatch queue (alos you are not using it correctly). The second point tries to use optional data not to use try/catch. Finally you could try to use Swift 5 together to the protocol Codable to have better code, simple and secure.
let url = URL(string: "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=439d4b804bc8187953eb36d2a8c26a02")!
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Error with the response, unexpected status code: \(String(describing: response))")
return
}
guard let data = data else {
return
}
guard let dictionaryObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return
}
if let main = dictionaryObj["main"] as? [String: Any], let temperature = main["temp"] {
DispatchQueue.main.async {
print("Temperature: \(temperature)")
}
}
}).resume()

setValuesForKeys resulting to this error: setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key type

This is the first time that I will be attempting to use the method setValuesForKeys and for some reason, I keep stumbling upon the error as stated below:
setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key type.
I've gone through several related questions here but to no avail. Here's my code below:
class ResumeCategory: NSObject {
var name: String?
var resumes: [Resume]?
static func getJSON() {
let urlString = "https://api.letsbuildthatapp.com/appstore/featured"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, _, error) in
DispatchQueue.main.async {
if let error = error {
print("Failed to get data from URL: ", error)
return
}
guard let data = data else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
print(json["categories"]!)
var resumeCategories = [ResumeCategory]()
for dict in json["categories"] as! [[String: Any]] {
let resumeCategory = ResumeCategory()
resumeCategory.setValuesForKeys(dict)
resumeCategories.append(resumeCategory)
}
} catch let error {
print("Failed to parse server response: ", error)
}
}
}.resume()
}

Load data from server using swift 4

I try to load the user profile like below
#IBAction func Btn_LoadDataFromDataBase(_ sender: UIButton) {
let myurl = "site.com/profile.php"
LoadURL(url: myurl)
}
func LoadURL(url: String) {
do{
let appURL = URL(string: url)! // convert string to URL
let data = try Data(contentsOf: appURL)
//error here on this line below :
let json1 = try JSONSerialization.jsonObject(with: data ) as! [String: Any]
print(json1)
let query1 = json1["profile"] as! [String: Any]
print(query1)
label_email.text = "Email : (query1["email"]!)"
}catch{
print("error in url")
}
}
if I test the json via webbrowser I get it like this:
{profile : [{"0":"999","id":"999","1":"1","email":"blabla#gmail.com","2":"1111","tel":"00122222222","3":"0" ..........
php code:
print "{profile : ".json_encode($user_profile,JSON_UNESCAPED_UNICODE)."}";
mysql_close($db);
?>
Please read the JSON carefully, there are only two different collection types
{} is dictionary ([String: Any])
[] is array ([Any] but in most cases [[String: Any]])
so the result for query1 (I changed the variable names to something more descriptive) is an array and you need a loop to print all elements:
let profileData = try JSONSerialization.jsonObject(with: data ) as! [String: Any]
let profiles = profileData["profile"] as! [[String: Any]] // could be even [[String:String]]
for profile in profiles {
print("Email :", profile["email"]!")
}
I'm wondering why so many owners of web services send the PHP arrays unnecessarily with both index and key.
And never load data from a remote URL synchronously, use asynchronous URLSession
You're better using URLRequest for async requests. You will need to pass your appURL as a parameter in a URLRequest and handle the answer in its completion handler.
An example:
let urlString = "https://swift.mrgott.pro/blog.json"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
// Implement JSON decoding and parsing
do {
let articlesData = try JSONDecoder().decode([OBJECT YOU WANT].self, from: data)
} catch let jsonError {
print(jsonError)
}
}.resume()

Struct Init with JSON and flatMap

I'm having a problem with the following code. I'm downloading a list of actors in JSON and I want to populate Struct Actor with the received data. Everything works great until I try to flatMap on the received data and try to initialize the struct Actor. When I try to compile the code i get the error: Cannot assign value of type '()' to type [Actor]. The error corresponds to a line in viewDidLoad actorsList = downloadActors() Would anybody have any recommendation who to solve this?
import UIKit
func downloadActors() {
var request = URLRequest(url: URL(string: "url...")!)
request.httpMethod = "POST"
let postString = "actorGroup=\("Superhero")"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
guard let data = data, error == nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("error : statusCode should be 200 but is \(httpStatus.statusCode)")
print("response = \(response)")
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode == 200 {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: AnyObject]
guard let actorsJSON = json?["response"] as? [[String : AnyObject]] else {
return
}
} catch {
print("catch error")
}
}
}
}
task.resume()
}
func loadActors() -> [Actor] {
if let actors = actorsJSON as? [[String : AnyObject]] {
return actors.flatMap(Actor.init)
}
}
let actorsArray = loadActors()
class MasterViewController: UITableViewController {
var actorsList = [Actor]()
var detailViewController: DetailViewController? = nil
var objects = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
actorsList = downloadActors()
print(actorsList)
Struct Actors is as follows:
struct Job {
let actorGroup: String
let actorName: String
}
extension Actor: JSONDecodable {
init?(JSON: [String : AnyObject]) {
guard let actorGroup = JSON["actorGroup"] as? String, let actorName = JSON["actorName"] as? String else {
return nil
}
self. actorGroup = actorGroup
self. actorName = actorName
}
}
let listActors = actorsJSON as? [[String : AnyObject]] {
Should be:
if let listActors = actorsJSON as? [[String : AnyObject]] {
Edit: For more info I'd like to add Vadian's comment:
Very confusing code. What does the function in the middle of the do block? Why do you type-check actorsJSON twice? The computed property is let listActors... which should be probably an optional binding (if let ... ). Further .mutableContainers is completely nonsense in Swift. And finally a JSON dictionary is [String:Any] in Swift 3.

Swift 3 Rest API not working

Having trouble with Rest API in Swift 3. Here's my code:
func getData()
{
let urlString = "http://dataservice.accuweather.com/locations/v1/regions?apikey=QVU3TATgJEdRyojFze6zivdrmiln9XlA"
let config = URLSessionConfiguration.default // Session Configuration
let session = URLSession(configuration: config) // Load configuration into Session
let url = URL(string: urlString)!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
print("in do block")
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
{
print("if condition is true")
//Implement your logic
print(json)
} else
{
print("Error in json serial")
}
} catch {
print("error in JSONSerialization")
}
}
})
task.resume()
}
After execution I can see the following print statements:
in do block
Error in son serial
Cannot figure out what is wrong with JSON Serialization command here. Expected responses is a JSON array. Any help would be appreciated. Thx
Change the
if let json = try JSONSerialization.jsonObject(with: data!, options:[]) as? [String: Any]
To
if let json = try JSONSerialization.jsonObject(with: data!, options:[]) as? [Any]
beacuse the json you have is "jsonWithArrayRoot" check this for further details.
https://developer.apple.com/swift/blog/?id=37