Get value of json response swift - ios

This is my code:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print(json)
let success = json ["success"] as? Int
print("Success: \(success)")
And this is my output:
{
error = "Account does not exist, please create it!";
}
Success: nil
`
So, before let success = json ["success"] as? Int, everything works well, but why is my output after this line nil?
This is my php:
public function login($username,$password) {
$query = "Select * from users where username = '$username' and password = '$password'";
$result = mysqli_query($this->connection, $query);
if (mysqli_num_rows($result) > 0) {
$json['success'] = 'Welcome '. $username . '!';
echo json_encode($json);
mysqli_close($this->connection);
} else {
$json['error'] = 'Account does not exist, please create it!';
echo json_encode($json);
mysqli_close($this->connection);
}

let success = json ["success"] as? Int
When you use this line it will extract the value of the key "success". As your json response does not contain that field it sets nil in the success variable.
Along with the error key you will need to return the success key too.

Success is nil because key 'success' does not exist in the JSON.
X as? Int = try to make x an Int from X when possible. If not possible (because the value is nil or the value is not convertible to an Int), make it Nil. That's what the question mark does.
So, I would do this:
if let success = json ["success"] as? Int {
print("Success: \(success)")
} else {
// Failed
}
You could also change your PHP code to make sure it always returns the 'success' key. However, I would recommend to use the Swift code above since you are always safe then.

Related

How to check if array contain null value and give default value swift

I have an array that's populated from a JSON response from an API server. Sometimes the values for a key in this array are Null
I am trying to take the given value and drop it into the detail text of a table cell for display.
The problem is that when I try to coerce the value into an String I get a crash, which I think is because I'm trying to coerce Null into a string.
What's the right way to do this?
ex-
my response is below type and I'm trying to fetch that array in self.imageArray variable
response = ["abc.jpg","null","xyzzy.jpg"]
self.imageArray = (self.dataArray.value(forKey: "product_image") as? [String])!
but at second iteration it gets crashed coz second value is null.
In your case only (Solution according to given question 'response'
array) :-
response = ["abc.jpg","null","xyzzy.jpg"]
Use following code
if !response.contains("") && !response.contains("null"){
// No null or empty string now
// your code
}else{
print("Contain null or empty value")
}
You can user compatcMap in this case.
let response = ["abc.jpg", nil, "xyzzy.jpg"]
let result = response.compactMap { $0 }
print(result)
If you are sure the value will be "null" in string type then you can use the following way.
let response = ["abc.jpg", "null", "xyzzy.jpg"]
let result = response.filter { $0 != "null" }
print(result)
the combined result is
let result = response.filter { $0 != "null" }.compactMap { $0 }
print(result)
This will handle the issue for both null and nil.
response = ["abc.jpg","null","xyzzy.jpg", nil]
var result = response.filter { return ($0 != "null" && $0 != nil) }
print(result) // return option result.
It should be like
var image = ["abc.jpg", nil, "xyzz.jpg"]
image = image.filter { $0 != nil}
print(image)
You have to filter out the nil values.
if you remove specific string "null"
var image = ["abc.jpg", "null", "xyzz.jpg"]
image = image.filter { $0 != "null"}
print(image)
If you know for sure that a valid value will always contain an image type like .jpg, then you can check against that and it will remove nil values, "null" or any other random strings, including empty strings " ".
response = ["abc.jpg","null","xyzzy.jpg", nil, " "]
self.imageArray = response.filter { $0?.contains(".jpg") ?? false }

How Fix Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 52."

How to Convert this one. "{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\";\n Name = Headquarters;\n}"; To this format {
"ID": "d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b",
"Name": "Headquarters"
}
if let jsonString = text as? String {
let objectData = jsonString.data(using: String.Encoding.utf8)
do {
let json = try JSONSerialization.jsonObject(with: objectData!, options: .allowFragments) as! [String:Any] //try JSONSerialization.jsonObject(with: objectData!, options: JSONSerialization.ReadingOptions.mutableContainers)
print(String(describing: json))
return json
} catch {
// Handle error
print(error)
}
}
Blockquote
First of all and already mentioned the string format is clearly not JSON.
It's the string format which is returned when calling the description property of a Foundation collection type (NSArray / NSDictionary).
For example a print statement calls description and this format appears also in output of Terminal.app.
However there is a solution: This string format is called openStep (an OpenStep / NeXt legacy format) and is available in PropertyListSerialization
This code reads the format:
let string = "{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\";\n Name = Headquarters;\n}"
let data = Data(string.utf8)
do {
let dictionary = try PropertyListSerialization.propertyList(from: data, format: nil)
print(dictionary)
} catch { print(error) }
Note:
I'm pretty sure that the original data format is not openStep and somewhere you created the string unnecessarily with the String(describing initializer like in the question.
your json format is incorrect. If you try it with jsonformatter it will throw this error:
so first you need to replace ; with ,. The second is that Strings should be wrapped in double quotes, replace Name = Headquarters with Name = "Headquarters".
This is the right form
{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\",
\n Name = "Headquarters"\n}

If let condition true when value is missing in optional type, swift

I have parser in Objc, parser returns NSDictionary. I am using this parser in swift class. But when some value is missing on that dictionary, it shows nil value. e.g. ->
wirlessData = {
"anon" = {
};
"channel" = {
"text" = 1;
};
}
I am checking through
if let wepauthValue = wirlessData["wepauth"] {
if let value = wepauthValue["text"] {
print("\(value)") // nil
}
}
I don't how it satisfy the if let condition. Any one faced this types of problem can help me out.
Thanks,
vikash
You don't need any special code to do this, because it is what a dictionary already does. When you fetch dict[key] you know whether the dictionary contains the key, because the Optional that you get back is not nil (and it contains the value).
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I have tested it and found that value is still optional.Take a look at screenshot below to understand it better.
"anon" would be an empty dictionary. An empty dictionary is not nil, it is a dictionary. Just an empty one. A JSON parser will never, ever give nil values unless you ask for a key that is not in a dictionary. For example wirlessData ["nonexistingkey"] would give you nil.
If you be more type-strong about it with the if..let's then:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? String {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match string at all")
}
}
or even more specifically in your case:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? Int {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match int at all")
}
}
The value your parser is returning not nil, its empty so you need to check on count if inner data type is dictionary or array, I have past 1 sample here
Please use below code and correct your logic accordingly to get it work properly
let wirlessData:[String:AnyObject] = [
"anon" : [],
"channel" : [
"text" : 1
]
]
if wirlessData["anon"]?.count > 0 {
if let value = wirlessData["anon"]!["text"] {
print("\(value)") // nil
}
}
Try this below code using type check operator (is) -
if wirlessData["anon"] is [String:AnyObject]
{
let anon = wirlessData["anon"]!
print(anon)
if anon["random"] is String {
let stringValue = anon["random"]!
print("\(stringValue)")
}
else if anon["random"] is Int
{
let intValue = anon["random"]!
print("\(intValue)") // nil
}
else
{
print(" may be value did't match string & Int or nil ")
}
}

Unable to get PFUser field

I want to get the xp of the current user and display it in a label. The xp field of the user is equal to 252 but it is displaying 0. I can get other fields like email, username and password but can't get the value for the xp field. Code:
xpRequiredLabel.text = "\(PFUser.currentUser()!["XP"])/300 XP"
What am I doing wrong ?
This expression PFUser.currentUser()!["XP"] returns AnyObject?. You need to unwrap this optional and cast it to string. Try this:
let userXP = PFUser.currentUser()!["XP"] as! String
xpRequiredLabel.text = "\(userXP)/300 XP"
Or this (less error-prone):
if let userXP = PFUser.currentUser()?["XP"] as? String {
xpRequiredLabel.text = "\(userXP)/300 XP"
}
Update
It turns out that you have to fetch the object from the server before accessing new properties. So, your code should look like:
let user = PFUser.currentUser()!
user.fetch()
let userXP = ["XP"] as! Int // If you have "Number" as your column datatype
xpRequiredLabel.text = "\(userXP)/300 XP"
Note that fetch() will block the UI. You can also make this code async:
if let user = User.currentUser() {
user.fetchInBackgroundWithBlock({ (result, error) -> Void in
if let u = result as? PFUser {
if let userXP = u["XP"] as? Int {
self.xpRequiredLabel.text = "\(userXP)/300 XP"
}
}
})
}
those are Int values
252 / 300 = 0 when ints invovled
you can do something like
xpRequiredLabel.text = "Float((PFUser.currentUser()!["XP"]))/300.0 XP"

Code Crashes when loading an empty attribute from Cloudkit - using Swift

I am trying to get access to a record value in CloudKit, here MyPin, it has a title & subtitle attribute/field value.
However it may happen that sometimes the record value is empty(here subtitle), and it crashes at the line when I call:
var tempS: String = Annot["Subtitle"] as! String
because Annot["Subtitle"] doesn exist ...
When I do
println(Annot["Subtitle"])
it returns nil
but if I do :
if (Annot["Subtitle"] == nil) {
println("just got a nil value")
}
I never enter the if statement:
Can someone help me how to identify if the record has an empty value?
Here is my line of codes:
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "MyPin", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for Annot in results {
var tempS: String = Annot["Subtitle"] as! String
}}
when you get Annot["Subtitle"] it will give you a CKRecordValue? return which has a base class of NSObjectProtocol. So in your case the field does exist but it's not a String so casting it using as! String will crash your app. Since the field exists the CKRecordValue will not be nil. However the content of that field is nil. When you print the field, it will output the .description of that field. In your case that is nil. Could you try this code instead:
if let f = Annot["Subtitle"] {
print("f = \(f) of type \(f.dynamicType)")
}
then set a breakpoint on the print line and when it stops try the following three statements in your output window:
po Annot
po f
p f
After the po Annot you should see what's in that record. Including your subtitle field. The po f is not so interesting. It will just output a memory address. The p f however will show you the actual type. If it's a string you should see something like: (__NSCFConstantString *) $R3 = 0xafdd21e0
P.S. Maybe you should call it record instead of Annot. It's a local variable so it should start with a lower case character. And it's still a record and not an Annot.
I think you are doing the right thing, but you don't see the println as it is executed in another thread (the completion part is executed asynchronously).
Try this:
if (Annot["Subtitle"] == nil) {
dispatch_async(dispatch_get_main_queue()) {
println("just got a nil value")
}
}
and see if it works!
The way I get values from cloudkit is this way. This both take care of the nil values and all other eventualities. Just note I have implemented a delegate to get my results back to the calling object asynchronously
privateDB.performQuery(query, inZoneWithID: nil) { (result, error) -> Void in
if error == nil{
for record in result{
let rec = record as! CKRecord
if let xxxVar = rec.valueForKey("fieldName") as? String{
myArray.append( xxxVar! ) //append unwrapped xxxVar to some result or whatever
}else{
//handle nil value
}
}
dispatch_async(dispatch_get_main_queue()) {
//do something with you data
self.delegate?.myResultCallBack(myArray)
return
}
}else{
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.myErrorCallBack(error)
return
}
}
}
Beware, there are some changes in Swift2

Resources