IOS Swift error reading Json String value - json

I am getting data from a URL and it is coming back in Json . What I am trying to do is color a certain button Blue if a particular Json column does not contain null or Nil . This is My Json
{"votes":"0","vote_status":null},{"votes":"1","vote_status":"11"}
as you can see the field vote_status returns as a String however if the value is null then it doesn't have any quotation marks around it . How can I check for Null values in my code
// This will store all the vote_status values
var VoteStatus = [String]()
// captures the value
if var vote_Status = Stream["vote_status"] as? String {
self.VoteStatus.append(vote_Status)
}
However I get an error fatal error: Index out of range
Which I am positive it is because the NuLL values does not have any strings . Is there a way I can check for NULL values and change them to something like "null" ? I have tried doing it this way
if var voteStatus = Stream["vote_status"] as? String {
if vote_Status == nil {
vote_Status = "null"
}
self.VoteStatus.append(vote_Status)
}
and it states that comparing non-optional value of type String to nil is always false . The code above compiles but gives an error on Runtime . I am new to Swift but any suggestions would be great..

The reason you're getting that compiletime error is that if this passes: if var voteStatus = Stream["vote_status"] as? String { then that is a guarantee that Stream["vote_status"] is a non-nil String value. If you want to do something different if that IS a nil, then just put an else statement:
if var voteStatus = Stream["vote_status"] as? String {
//Do whatever you want with a guaranteed, non-nil String
} else {
//It's nil
}
If you also want to treat the string "null" as a nil value, you can add one little bit:
if var voteStatus = Stream["vote_status"] as? String, voteStatus != "null" {
//Do whatever you want with a guaranteed, non-nil, non-"null" String
} else {
//It's nil or "null"
}
The index out of range error is likely caused by something that we're not seeing in your code. Is Stream itself an optional? In your second example are you forgetting to initialize your voteStatus array?

Related

Why value returned from JSON is not comparable to NSNull?

I am returning String values from API via Swift 4 JSON Codable method.
I know few values are "null" or nil, so to avoid crashes I am trying to implement code. Here is the code giving the subject error (on NSNull comparison):
if Cur[indexPath.row].cap == nil || Cur[indexPath.row].cap == NSNull {
print("Could not find the value")
CapVal = "N/A"
} else {
CapVal = Cur[indexPath.row].cap!
}
The error:
Binary operator '==' cannot be applied to operands of type 'String?' and 'NSNull.Type
I tried to cast it as String too: Cur[indexPath.row].cap as? String still got the same error.
If you are using JSONDecoder, both missing values and values that are explicitly designated as null will be returned as nil:
Consider this JSON:
{"foo": "a", "bar": null}
And this struct:
struct Result: Decodable {
var foo: String
var bar: String?
var baz: String?
}
If you use JSONDecoder, you can just do:
guard let result = try? JSONDecoder().decode(Result.self, from: data) else { ... }
let bar = result.bar ?? "N/A"
I know you were asking about Codable in Swift 4, but just for your reference, if you were using JSONSerialization, though, you could theoretically test for null, because JSONSerialization does return null values as NSNull:
guard let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else { ... }
let bar = json["bar"]
if bar == nil || bar is NSNull {
// bar was either not found or `null`
} else {
// bar was found and was not `null`
}
Personally, though, I'd just optionally cast to string and use nil coalescing operator if the cast failed, e.g.
let bar = (json["bar"] as? String) ?? "N/A"
But, this is all moot with Swift 4's JSONDecoder.

swift how can I check for NULL values coming from Json

I have a rest api and am getting all data via Json then putting it in a IOS TableView. My issue is that some data is being returned as NULL in Json
"vote_status":null
I am trying to get that NULL value in swift and change it to a string "0" but am having a hard time doing so . I have this so far
if var vote_status = Stream["vote_status"] as? String {
if (vote_status == (vote_status)[NSNull]) {
vote_status = "0"
}
}
However I get this compile error:
Cannot subscript a value of type 'String' with an index of type
'(NSNull).Type' (aka 'NSNull.Type')
I am doing this because nil and null does not seem to work so I can't do this.
if (vote_status == nil) ...
You just need to conditionally cast your dictionary value to String and use the Nil Coalescing Operator ?? to assign "0" in case of failure null:
let vote_status = Stream["vote_status"] as? String ?? "0"
Swift 3.0
func checkNull(obj : AnyObject?) -> AnyObject? {
if obj is NSNull {
return nil
} else {
return value
}
}
object.feature = checkNull(dict["feature"])
try this
vote_status is NSNull
You can try this
func checkForNull(value:AnyObject) -> String
{
if(value as! NSObject == NSNull() || value as! String == "")
{
return " "
}
else
{
return value as! String
}
}
Try something like this:
if let category = Stream["vote_status"] as? String {
print(category)
} else {
print(category)
}

Check if JSON as dictionary contains Optional(null)

I want to make an if statement that checks if my JSON (item_section) has a null value at a certain key.
This code:
let my_dict = item_section[counter].dictionaryValue
print(my_dict["creator"])
prints: Optional(null) when the creator is not set.
If it is set if it prints the creator's name, like: user_729834892.
How can I make an if statement that checks if the creator is null?
Such as:
if ((my_dict["creator"]) == nil) { //This line does not work
my_dict["creator"] = "No Maker"
}
Try
if my_dict["creator"].type == .Null {
print("creator is null")
}
try this
print( my_dict.indexForKey( "creator") )
if (my_dict.indexForKey( "creator") == nil) {
my_dict["creator"] = "No Maker"
}
if the creator is not set then function indexForKey will return nil.
The JSON framework never returns an optional when indexing a dictionary (a JSON object). If the value doesn't exist, it rather returns the constant JSON.null, which you can compare:
if my_dict["creator"] == JSON.null {
my_dict["creator"] = "No Maker"
}
also method isExists would work
if !my_dict["creator"].isExists() {
my_dict["creator"] = "No Maker"
}

Casting AnyObject to Double

I am trying to parse JSON with the following code:
func ltchandler(response: NSURLResponse!, data : NSData!, error : NSError!) { //Is passed the results of a NSURLRequest
if ((error) != nil) {
//Error Handling Stuff
} else {
if (NSString(data:data, encoding:NSUTF8StringEncoding) == "") {
//Error Handling Stuff
} else {
var data = NSData(data: data);
// Define JSON string
var JSONString = "\(data)"
// Get NSData using string
if let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
// Parse JSONData into JSON object
var parsingError: NSError?
if let JSONObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parsingError) as? [String: AnyObject] {
// If the parsing was successful grab the rate object
var rateObject: Double! = JSONObject["price"]?.doubleValue
// Make sure the rate object is the expected type
if let rate = rateObject as? Double! { // THIS IS NOT WORKING!!!
//Do stuff with data
} else {
println("Parsing Issue")
}
}
}
}
}
}
The line marked THIS IS NOT WORKING!!! is not being called.
From what I can tell, it cannot cast rateObject as a double - why not? It is not showing any errors.
To clarify, the expected behavior is that a double is created from the JSON object.
To strictly answer your question have you tried printing the rateObject. Also why are you casting to Double! rather than just Double in the problematic line?
Personally I don't use ! in almost all cases. You are better off using either non-optionals or proper optionals.
In the relevent section I would write:
// Make sure the rate object is the expected type
if let rate = JSONObject["price"]?.doubleValue {
//Do stuff with rate
} else {
print("Parsing Issue")
}
Of course if the JSONObject["price"] is not something with a doubleValue method or the method returns nil you will end up with nil and the else case being taken.
the code worked for me, try this code:
// if the value equals nil or any String, the instruction abort the if
// SWIFT 2.0 in xcode beta 5
if let rate = Double((JSONObject["price"] as? String)!){
// insert you code here
} else {
print("error message")
}

How do I save JSON array of dictionaries in Swift that maps a String to an Int or String?

I'm having a lot of difficulty with this one.
My server sends JSON arrays of dictionaries, with the dictionaries having a String as a key, with either a String or an Int as the value for the key. For example, if the key was name, it would return a string, but some values are asking for numeric things like "time since" which return Ints.
How do I handle this in Swift?
My first attempt was:
let dictArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &jsonError) as Dictionary<String, Any>[]
But I get:
fatal error: can't unwrap Optional.none
If I change Any to AnyObject I can't cast it as an Int for some keys, it complains about the subscript.
What should I be doing?
The Cocoa to Swift binding maps id as AnyObject. And since the keys are not guaranteed to exist in the dictionary, the subscript returns AnyObject?.
Along those lines still seems to be problem with Xcode beta2.
For example, this crashes reproducibly the swift REPL:
let a : AnyObject? = nil
let b : Any? = a
So that might be the reason as well, why casting to Dictionary<String, Any>[] does not work.
Either way you might be better off using the "literal" mapping Dictionary<String, AnyObject>[] and checking the types yourself.
When casting AnyObject? to Int you have to remember that you are actually dealing with an optional. That means you have to unwrap it first using ! or an if let construct.
Alternatively you can just iterate over the dictionary:
var jsonError : NSError?
if var dictArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &jsonError) as? Dictionary<String, AnyObject>[]
{
for dict in dictArray
{
for (key, data) in dict
{
var output : String = "(unknown)";
if let number = data as? Int
{
output = "\(number)"
}
else if let str = data as? String
{
output = str
}
println("\(key): \(output)")
}
}
}