How to detect null JSON value in Swift 3? - json

I have a JSON object like this:
{
"access_token" = 593d6d5d5eca0;
"expires_in" = never;
user = {
fullname = name;
"profile_picture_url" = "<null>";
};
}
And here is my code to parse "profile_picture_url":
let profPicURL = URL(string: userData["profile_picture_url"] as! String)
let profPicData = NSData(contentsOf: profPicURL!)
let profilePicture = UIImage(data: profPicData as! Data)
But I got an error since the value of "profile_picture_url" was null.
How to parse "profile_picture_url" in safe way?

use if let
if let profileImageString = userData["profile_picture_url"] as? String {
let profPicURL = URL(string: "Hello moto")
let profPicData = try? Data(contentsOf: profPicURL!)
if let profPicData = profPicData {
let profilePicture = UIImage(data: profPicData)
}
} else {
// "profile_picture_url" was null
}

Related

How can I restore my old task with a new one in swift?

I have question about tasks. I need to restore my request, I change link and fetch some new data to that link and show them on my table view. User can change link according to picker view, I have a variable for it and I replaced in link and thats working correct too but in second request can make a thread I assume it is very bad question but I am new in swift. How can I make second or more request in one function.
Here my function code :
func fetchArticles(){
let urlRequest = URLRequest(url: URL(string: "my_api_link_is_here")!)
let task = URLSession.shared.dataTask(with: urlRequest) { (Data,URLResponse,Error) in
if Error != nil {
print(Error!)
}
self.articles = [Article]()
do{
let json = try JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJson = json["articles"] as? [[String:AnyObject]] {
for articleFromJson in articlesFromJson {
let article = Article()
let source = articleFromJson["source"] as![String: AnyObject]
let name = source["name"]
if let title = articleFromJson["title"] as? String, let author = name as? String , let desc = articleFromJson["description"] as? String, let url = articleFromJson["url"] as? String, let imageToUrl = articleFromJson["urlToImage"] as? String {
article.author = author as String
if articleFromJson.index(forKey: "description") != nil {
article.desc = desc as String
}else{
article.desc = "empty"
}
article.headline = title as String
article.imageUrl = imageToUrl as String
article.url = url as String
}
self.articles?.append(article)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch let Error {
print(Error)
}
}
task.resume()
}

Networking using JSONDecoder & codable protocol

I am wondering what i am doing wrong . I am trying to understand how to use urlsession and codable protocol using JSONDecoder. When i use JSONDecoder i am getting the following error message :
keyNotFound(CodingKeys(stringValue: "name", intValue: nil), my resaponse contain ''name'' . But when i use JSONSerialization, I am able to print the response . If someone can explain me.
Code using JSONDecoder
struct Business:Codable {
let name: String
enum CodingKeys: String, CodingKey {
case name = "name"
}
init(from decoder: Decoder) throws {
let value = try decoder.container(keyedBy: CodingKeys.self)
self.name = try value.decode(String.self, forKey:CodingKeys.name)
}
}
let task = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
print(response)
} else{
print("error")
}
guard let data = data else {return}
do {
let business = try JSONDecoder().decode(Business.self, from: data)
print(business.name)
} catch {
print("Error parsing JSON: \(error)")
}
}
task.resume()
Code using JSONSerialization
struct Business: Decodable {
let name: String
let displayAddress: String
let categories: String
let imageUrl : String
init(json: [String:Any]) {
name = json["name"] as? String ?? ""
displayAddress = json["location"] as? String ?? ""
categories = json["categories"] as? String ?? ""
imageUrl = json["image_url"] as? String ?? ""
}
}
let task = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
print(response)
} else{
print("error")
}
guard let data = data else {return}
do {
if let myjson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? Dictionary<String,Any> {
print(myjson)
}
} catch {
print("Error parsing ")
}
}
task.resume()
The response
["region": {
center = {
latitude = "43.67428196976998";
longitude = "-79.39682006835938";
};
}, "businesses": <__NSArrayM 0x60000211cff0>(
{
alias = "pai-northern-thai-kitchen-toronto-5";
categories = (
{
alias = thai;
title = Thai;
}
);
coordinates = {
latitude = "43.647866";
longitude = "-79.38864150000001";
};
"display_phone" = "+1 416-901-4724";
distance = "3010.095870925626";
id = "r_BrIgzYcwo1NAuG9dLbpg";
"image_url" = "https://s3-media3.fl.yelpcdn.com/bphoto/t-g4d_vCAgZH_6pCqjaYWQ/o.jpg";
"is_closed" = 0;
location = {
address1 = "18 Duncan Street";
address2 = "";
address3 = "";
city = Toronto;
country = CA;
"display_address" = (
"18 Duncan Street",
"Toronto, ON M5H 3G8",
Canada
);
state = ON;
"zip_code" = "M5H 3G8";
};
name = "Pai Northern Thai Kitchen";
phone = "+14169014724";
price = "$$";
rating = "4.5";
"review_count" = 2405;
transactions = (
);
url = "https://www.yelp.com/biz/pai-northern-thai-kitchen-toronto-5?adjust_creative=A4ydpSOHv8wBNquTDeh0DQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=A4ydpSOHv8wBNquTDeh0DQ";
},
Business is not the root data object in your JSON. You need something like this:
struct Business: Codable {
let name: String
}
struct RootObject: Codable {
let businesses: [Business]
}
let rootObject = try JSONDecoder().decode(RootObject.self, from: data)
print(rootObject.businesses.first?.name)

parsing Json in swift4

hello i try to decode Json:
{"result":[
{"ID":"80",
"time":"09:00:00",
"status":[
{"status":0,"kirpeja_id":"74","name":"Natalja","image":"natalija255.png","duration":"00:20:00"},
{"status":1,"kirpeja_id":"80","name":"Lina","image":"kazkas.png","duration":"00:30:00"},
{"status":0,"kirpeja_id":"82","name":"Rasa ","image":"IMG_20170906_171553.jpg","duration":"00:40:00"}
]},
{"ID":"81",
"time":"09:10:00",
"status":[
{"status":0,"kirpeja_id":"66","name":"Ilona","image":"ilona_new.jpg","duration":"00:30:00"},
{"status":0,"kirpeja_id":"74","name":"Natalja","image":"natalija255.png","duration":"00:20:00"},
{"status":0,"kirpeja_id":"80","name":"Lina","image":"kazkas.png","duration":"00:30:00"},
{"status":0,"kirpeja_id":"82","name":"Rasa ","image":"IMG_20170906_171553.jpg","duration":"00:40:00"}
]},
...
here my classes
class TimeStatusResult: Codable {
let result: [TimeStatus]
init (result:[TimeStatus]) {
self.result = result
}
}
class TimeStatus: Codable {
let ID:String?
let time: String?
let status: [Status]
init (status:[Status]) {
self.ID = ""
self.time = ""
self.status = status
}
}
class Status: Codable {
let status: String?
let kirpeja_id: String?
let name: String?
let image: String?
let duration: String?
init () {
self.status = ""
self.kirpeja_id = ""
self.name = ""
self.image = "nophoto.jpg"
self.duration = ""
}
}
here my json function
final let jsonUrl = URL(string: "http://**********/getlaikas_new.php")
private var timeStatusResult = [TimeStatus]()
func downloadJson () {
guard let downloadURL = jsonUrl else {return}
var request = URLRequest(url: downloadURL)
request.setValue("application/x-www-form-urlencoded",forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "data=\(pInfo.paslaugosData!)&salonId=\(pInfo.ID!)&paslaugos_id=\(pInfo.paslaugosId!)"
request.httpBody = postString.data(using: .utf8, allowLossyConversion: true)
URLSession.shared.dataTask(with: request) {data, urlResponse, error in
guard let data = data , error == nil, urlResponse != nil else {
print ("something wrong")
return }
print ("downloaded!")
do
{
let decoder = JSONDecoder()
print (data)
let downloadedTimeStatus = try decoder.decode(TimeStatusResult.self, from: data)
self.timeStatusResult = downloadedTimeStatus.result
DispatchQueue.main.async {
// self.kirpejosPaslaugosTable.reloadData()
}
} catch {
print ("something wrong after download")
}
}.resume()
}
in this line i have issue
let downloadedTimeStatus = try decoder.decode(TimeStatusResult.self, from: data)
somebody can help me? :(
The error is very clear:
...burzua_1.Status.(CodingKeys in _479ABD1AF7892C9F2FD23EC23214E088).status], debugDescription: "Expected to decode String but found a number instead."
The value for key status is not in double quotes so it's an Int
class Status: Codable {
let status: Int
...
Please don't declare all properties carelessly as optional. For example status as well as all other keys is present in all Status dictionaries.

How to get a JSON object where a row is equal to variable in Swift

Hy everyone. I am working on an app which works with API's. I am trying to get the "Name" where the "Id" is equal to 1000. When I print the Name it gives me a String value "Todd".
can anyone help me ? This is my JSON response.
And this is my code.
func apiRequestCompani(){
for index in companyId {
let config = URLSessionConfiguration.default
let username = "F44C3FC2-91AF-5FB2-8B3F-70397C0D447D"
let password = "G23#rE9t1#"
let loginString = String(format: "%#:%#", username, password)
let userPasswordData = loginString.data(using: String.Encoding.utf8)
let base64EncodedCredential = userPasswordData?.base64EncodedString()
let authString = "Basic " + (base64EncodedCredential)!
print(authString)
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
let urlProjects = NSURL(string: "https://start.jamespro.nl/v4/api/json/company/"+index+"/?limit=10")
let task = session.dataTask(with: urlProjects! as URL) {
( data, response, error) in
if let taskHeader = response as? HTTPURLResponse {
print(taskHeader.statusCode)
}
if error != nil {
print("There is an error!!!")
print(error)
} else {
if let content = data {
do {
let dictionary = try JSONSerialization.jsonObject(with: content) as! [String:Any]
print(dictionary)
if let items = dictionary["items"] as? AnyObject {
if let klantId = items["Id"] as? String {
if klantId == "1000" {
//print(klantId)
}
}
if let name = items["Name"] as? String {
self.companyName.append(name)
//print(self.companyName)
}
}
}
catch {
print("Error: Could not get any data")
}
}
}
}
task.resume()
//print( urlProjects)
}
}
I think you can do something like this,
var dict: [AnyHashable: Any]? = (response.responseDict()["items"] as? [AnyHashable: Any])
if (dict?.value(forKey: "BranchId") == "1000") {
var name: String? = (dict?.value(forKey: "Name") as? String)
}
Please try the above code snippet.
Hope this will help you.
You can try with below code
let companyIds = ["1000", "1001"]
var companyName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.apiRequestCompani { (names) in
self.companyName = names // companyName contains all names where id == 1000
print("companyName === \(self.companyName)")
}
}
func apiRequestCompani(completion: #escaping ([String]) -> ()) {
var names = [String]()
var resCount = 0
for companyId in companyIds {
let config = URLSessionConfiguration.default
let username = "F44C3FC2-91AF-5FB2-8B3F-70397C0D447D"
let password = "G23#rE9t1#"
let loginString = String(format: "%#:%#", username, password)
let userPasswordData = loginString.data(using: String.Encoding.utf8)
let base64EncodedCredential = userPasswordData?.base64EncodedString()
let authString = "Basic " + (base64EncodedCredential)!
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
let urlProjects = NSURL(string: "https://start.jamespro.nl/v4/api/json/company/"+companyId+"/?limit=10")
let task = session.dataTask(with: urlProjects! as URL) {
( data, response, error) in
if let taskHeader = response as? HTTPURLResponse {
print(taskHeader.statusCode)
}
if error != nil {
print("There is an error!!!")
print(error ?? "")
} else {
if let content = data {
do {
let dictionary = try JSONSerialization.jsonObject(with: content) as! [String:Any]
if let items = dictionary["items"] as? AnyObject {
if let klantId = items["Id"] as? String, klantId == "1000" {
if let name = items["Name"] as? String {
print("NAME === \(name)")
names.append(name)
}
}
}
}
catch {
print("Error: Could not get any data")
}
}
}
resCount = resCount + 1
if self.companyIds.count == resCount {
completion(names)
}
}
task.resume()
//print( urlProjects)
}
}

Deserialize a Dictionary (JSON) to a swift object

I'm trying to build a login function (POST method) and the resultant is a JSON with user details and few other details. I have created a class with all the fields I need to use from the result of POST call. But I'm facing an issue with deserialzing the json to the object of the class. Can some one help me with this. (I have seen similar questions on SO and tried solving using the solution. I have tried converting the json to string and then to swift object using var UserDetails = UserDetails(json:jsonString)
)
My code:
class UserDetails {
let token:String
let agent_id: Int
let user_id:Int
let company_id:Int
let affliate_Id:Int
let role_id:Int
let username: String
let surname:String
let lastname:String
init(token:String,agent_id: Int,user_id:Int,company_id:Int,affliate_Id:Int,role_id:Int,username: String,surname:String,lastname:String) {
self.token = token;
self.agent_id = agent_id;
self.user_id = user_id;
self.company_id = company_id;
self.affliate_Id = affliate_Id;
self.role_id = role_id;
self.username = username;
self.surname = surname;
self.lastname = lastname;
} }
My controller class:
let task = session.dataTask(with: request as URLRequest) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
NSLog("Login SUCCESS");
let prefs:UserDefaults = UserDefaults.standard
prefs.set(username, forKey: "USERNAME")
prefs.set(udid, forKey: "UDID")
prefs.synchronize()
print("Response: \(json)")
//var jsonString = NSString(data: json, encoding: String.Encoding.utf8)! as String
//when I tried to do the above statement, an error is thrown. Cannot convert value of type NSDictionary to expected argument type Data
//var person:UserDetails = UserDetails(json: jsonString)
self.dismiss(animated: true, completion: nil)
} else {
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)// No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError)// Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
JSON Response:
{
"user": {
"token": "ABCDEFGHI",
"agent_id": 0,
"user_id": 151,
"company_id": 1,
"affiliate_Id": 0,
"role_id": 1,
"username": "testman1",
"surname": "Test",
"lastname": "man",
},
"menu": [
{ .....
Can someone help me in solving this. Tia
You should avoid using Foundation classes (NSDictionary etc) and use Swift types.
I also suggest you add a failable initialiser to your UserDetails class that accepts a dictionary:
class UserDetails {
let token: String
let agentId: Int
let userId: Int
let companyId: Int
let affliateId: Int
let roleId: Int
let username: String
let surname: String
let lastname: String
init?(dictionary: [String:Any]) {
guard let token = dictionary["token"] as? String,
let agentId = dictionary["agent_id"] as? Int,
let userId = dictionary["user_id"] as? Int,
... // And so on
else {
return nil
}
self.token = token;
self.agentId = agentId;
self.userId = userId;
self.companyId = companyId;
self.affliateId = affliateId;
self.roleId = roleId;
self.username = username;
self.surname = surname;
self.lastname = lastname;
}
}
and in your completion block:
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any] {
if let userDict = json["user"] as [String:Any] {
guard let userObject = UserDetails(dictionary:userDict) else {
print("Failed to create user from dictionary")
return
}
// Do something with userObject
}
}
} catch let parseError {
I also took the liberty of removing the _ from your properties because _ are icky
First of all you need to use Swift native Dictionary instead of NSDictionary also batter if you define your init method of UserDetails with single parameter of type [String: Any].
class UserDetails {
var token:String = ""
var agent_id: Int = 0
var user_id:Int = 0
var company_id:Int = 0
var affliate_Id:Int = 0
var role_id:Int = 0
var username: String = ""
var surname:String = ""
var lastname:String = ""
init(userDic: [String: Any]) {
if let token = user["token"] as? String, let agent_id = user["agent_id"] as? Int,
let user_id = user["user_id"] as? Int, let company_id = user["company_id"] as? Int,
let affliate_Id = user["affliate_Id"] as? Int, let role_id = user["role_id"] as? Int,
let username = user["username"] as? String, let surname = user["surname"] as? String,
let lastname = user["lastname"] as? String {
self.token = token;
self.agent_id = agent_id;
self.user_id = user_id;
self.company_id = company_id;
self.affliate_Id = affliate_Id;
self.role_id = role_id;
self.username = username;
self.surname = surname;
self.lastname = lastname;
}
}
}
Now simply call this init method from your json response like this.
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any], let userDic = json["user"] as? [String: Any]{
let userDetails = UserDetails(userDic: userDic)
}