I am parsing a JSON response and trying to check if one of my keys is null. How would I go about this? I have the following:
var routingNumber = (dic.value(forKey: "result") as! NSDictionary).value(forKey: "routingNumber") as! String
and this returns:
Could not cast value of type 'NSNull' (0x107d238c8) to 'NSString' (0x107329c40).
How would I check if the value is NSNULL?
if( something != NSNULL){
do something
}else{
do something else
}
You can extract value from dic like this.
if let value = (dict["key"] as? String)
{
//NOT NULL
}
else
{
//NULL
}
create below function
func isNsnullOrNil(object : AnyObject?) -> Bool
{
if (object is NSNull) || (object == nil)
{
return true
}
else
{
return false
}
}
call function where you want to check for null or nil value
if isNsnullOrNil((dic.value(forKey: "result") as! NSDictionary).value(forKey: "routingNumber"))
{
print("object is null or nil")
}
else
{
print("object is not null or nil")
}
I had this same problem once.
CHECK FOR IF NSNULL
if let result = dic["result"] as? NSDictionary {
// There is a dictionary
if let routingNumber = result["routingNumber"] as? String {
// There is a routingNumber
}
else if let routingNumber = result["routingNumber"] as? NSNull {
// There is routingNumber but Null
}
else {
// No routingNumber
}
}
That should do the trick.
if let result = dict["result"] as? [String:Any], let routingNumber = result["routingNumber"] as? String {
print("the routingNumber is \(routingNumber)")
} else {
print("nil")
}
Related
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)
}
I am playing With JSON for last two days and facing alot of curious problems and thanks to stack overflow it helps me. This is JSON featured key has two types of String values.
"featured":"1"
or
"featured": null,
I tried a lot to handle this but failed
Step 1:
if dict.objectForKey("featured") as? String != nil {
featured = dict.objectForKey("featured") as? String
}
Step 2:
let null = NSNull()
if dict.objectForKey("featured") as? String != null {
featured = dict.objectForKey("featured") as? String
}
Step 3:
if dict.objectForKey("featured") as? String != "" {
featured = dict.objectForKey("featured") as? String
}
but unfortunately can't found solution, you answer will be appreciated.
Try This
func nullToNil(value : AnyObject?) -> AnyObject? {
if value is NSNull {
return nil
} else {
return value
}
}
object.feature = nullToNil(dict["feature"])
Here, you can use this method, which will convert null value to nil and wont' cause crash in your app.
You can also use as?
object.feature = dict["feature"] as? NSNumber
Thanks.
Here is a working code, type cast operator(as?) will do the trick here. Null will not be typecasted into String, so the execution will go to failure block.
if let featured = dict["featured"] as? String {
print("Success")
}
else {
print("Failure")
}
Try this!
if let demoQuestion = dict.objectForKey("featured"){
let getValue: String = demoQuestion as! String
}
else {
print("JSON is returning nil")
}
Optional chaining with if let or its counterpart guard let is the way to go. All three steps combined (missing, wrong type - NSNull too, empty string):
guard let featured = dict.objectForKey("featured") as? String where !value.isEmpty else {
print("featured has wrong value")
}
// do what you need to do with featured
If you want to know more about optional chaining check out documentation
Hi you can use below function to remove null to empty string and prevent crashes
func removeNullFromDict (dict : NSMutableDictionary) -> NSMutableDictionary
{
let dic = dict;
for (key, value) in dict {
let val : NSObject = value as! NSObject;
if(val.isEqual(NSNull()))
{
dic.setValue("", forKey: (key as? String)!)
}
else
{
dic.setValue(value, forKey: key as! String)
}
}
return dic;
}
and before giving dict to any method call function in below way
let newdict = self.removeNullFromDict(dict: dict);
i did a static func to convert value from json to optional String.
class Tools{
static func setOptionalStr(value : Any?) -> String?{
guard let string = value as! String?, !string.isEmpty else {
return nil
}
return value as? String
}
}
In my controller
let urlStats: String? = Tools.setOptionalStr(value: json["UrlStats"])
i'm open to your feedback
I have this working but it seems like a very manual process and I can't work out how to loop inside a loop (or if I should). Right now I am just testing this with 3 variables, but there will ultimately be about 100. Here's my playground. Is there a way to simplify this so I don't have to manually add each array name?
import Foundation
var json_data_url = "216.92.214.107/data_test.json"
var LRKSFOweekdayDep : [String] = [String]()
var LRKSFOweekendDep : [String] = [String]()
var SFOLRKweekdayDep : [String] = [String]()
let journeysURL:NSURL = NSURL(string: json_data_url)!
let data = NSData(contentsOfURL: journeysURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
print(json)
if let dep_obj = json as? NSDictionary {
if let array_journey = dep_obj["journey"] as? NSArray{
if let journies = array_journey[0] as? NSDictionary {
if let array_dep = journies["LRKSFOweekdayDep"] as? NSDictionary{
if let dep = array_dep["dep"] as? NSArray {
for var i = 0; i < dep.count; ++i
{
let add = dep[i] as! String
LRKSFOweekdayDep.append(add)
}
print(LRKSFOweekdayDep)
}
}
}
if let journies = array_journey[1] as? NSDictionary {
if let array_dep = journies["LRKSFOweekendDep"] as? NSDictionary{
if let dep = array_dep["dep"] as? NSArray {
for var i = 0; i < dep.count; ++i
{
let add = dep[i] as! String
LRKSFOweekendDep.append(add)
}
print(LRKSFOweekendDep)
}
}
}
if let journies = array_journey[2] as? NSDictionary {
if let array_dep = journies["SFOLRKweekdayDep"] as? NSDictionary{
if let dep = array_dep["dep"] as? NSArray {
for var i = 0; i < dep.count; ++i
{
let add = dep[i] as! String
SFOLRKweekdayDep.append(add)
}
print(SFOLRKweekdayDep)
}
}
}
}
}
} catch {
print("error serializing JSON: \(error)")
}
You might want to look at using SwiftyJSON to make the parsing easier.
Right now, you have something like:
if let dep = array_dep["dep"] as? NSArray {
for var i = 0; i < dep.count; ++i {
let add = dep[i] as! String
LRKSFOweekendDep.append(add)
}
}
That can be simplified to:
LRKSFOweekendDep = array_dep["dep"] as? [String]
That assumes of course, that you define LRKSFOweekendDep to be optional. If it's not optional, you can do:
LRKSFOweekendDep = array_dep["dep"] as? [String] ?? []
But, it should be optional.
In a comment, you say that there are going to be 100 of these. Rather than having a variable for each, I would have thought that you'd rather keep an array of objects. For example, consider:
struct Journey {
let name: String
let departures: [String]
}
Then, to parse your JSON, you could iterate through the results:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
var journeys = [Journey]()
if let results = json as? [String: AnyObject], let array = results["journey"] as? [[String: AnyObject]] {
for dictionary in array {
for (name, departures) in dictionary {
if let departureDictionary = departures as? [String: [AnyObject]], let departureList = departureDictionary["dep"] as? [String] {
journeys.append(Journey(name: name, departures: departureList))
}
}
}
}
Finally, I would advise against NSData(contentsOfURL:), because that's synchronous. Use NSURLSession's dataTaskWithURL, which is asynchronous. Also, if you use data! pattern, first check to make sure it's not nil. Otherwise, if data was nil for any reason outside of your control (e.g. the web server is down, internet is temporarily interrupted, etc.), the app will crash rather than handling it gracefully.
Putting that all together, you get something like:
func retrieveJourneys(completionHandler: ([Journey]?, NSError?) -> ()) {
let task = NSURLSession.sharedSession().dataTaskWithURL(journeysURL) { data, response, error in
guard error == nil && data != nil else {
completionHandler(nil, error)
return
}
var json: [String: AnyObject]?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String: AnyObject]
} catch let parseError as NSError {
completionHandler(nil, parseError)
}
var journeys = [Journey]()
if let array = json!["journey"] as? [[String: AnyObject]] {
for dictionary in array {
for (name, departures) in dictionary {
if let departureDictionary = departures as? [String: [AnyObject]], let departureList = departureDictionary["dep"] as? [String] {
journeys.append(Journey(name: name, departures: departureList))
}
}
}
}
completionHandler(journeys, nil)
}
task.resume()
}
And then you'd use it like so:
var journeys: [Journey]?
override func viewDidLoad() {
super.viewDidLoad()
retrieveJourneys { journeys, error in
guard error == nil && journeys != nil else { // make sure it didn't have network problem
print(error)
return
}
dispatch_async(dispatch_get_main_queue()) { // now update model on main queue
self.journeys = journeys
// and, for giggles and grins, this is how you might grab the first one and examine it:
let someJourney = self.journeys![0]
print(someJourney.name)
print(someJourney.departures)
}
}
}
Now, the above assumes that you wanted an ordered list of journeys, sorted by the order you received them.
On the other hand, if you didn't care about the order, but wanted an efficient way to retrieve the departures associated with a given key, you might use a dictionary, instead:
func retrieveDepartures(completionHandler: ([String: [String]]?, NSError?) -> ()) {
let task = NSURLSession.sharedSession().dataTaskWithURL(journeysURL) { data, response, error in
guard error == nil && data != nil else {
completionHandler(nil, error)
return
}
var json: [String: AnyObject]?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String: AnyObject]
} catch let parseError as NSError {
completionHandler(nil, parseError)
}
var departures = [String: [String]]()
if let array = json!["journey"] as? [[String: AnyObject]] {
for dictionary in array {
for (name, departureObject) in dictionary {
if let departureDictionary = departureObject as? [String: [AnyObject]], let departureList = departureDictionary["dep"] as? [String] {
departures[name] = departureList
}
}
}
}
completionHandler(departures, nil)
}
task.resume()
}
And then:
var departures: [String: [String]]?
override func viewDidLoad() {
super.viewDidLoad()
retrieveDepartures { departures, error in
guard error == nil && departures != nil else {
print(error)
return
}
dispatch_async(dispatch_get_main_queue()) {
self.departures = departures
// and, for giggles and grins, this is how you might grab a list of departures given a particular key
let departureTimes = self.departures!["LRKSFOweekdayDep"]
print(departureTimes)
}
}
}
When I print(JSON) I get the files, so the .request works.
But when I am trying to access the "test" key (which exists) I get nil
I get
"I am here"
"now ,I am here"
Alamofire.request(.GET, self.APIBaseUrl , parameters: ["api_key": self.APIkey])
.responseJSON { response in
if let JSON = response.result.value {
print("I am here")
if let str = JSON as? NSDictionary {
print("now , I am here")
if let movieUrlString = str["poster_path"] as? String)! {
print("but now here")
}
EDITED
print(dict)
**dates** = {
maximum = "2015-10-21";
minimum = "2015-09-30";
};
page = 1;
**results** = (
{
adult = 0;
"poster_path" = "/2XegKZ0I4QrvzpEHneigRk6YTB1.jpg";
++(more results)
Try to use more meaningful debug printing statements and variables names. Also you were not using the right variable for subscripting. Fixed example:
Alamofire.request(.GET, self.APIBaseUrl , parameters: ["api_key": self.APIkey]).responseJSON { response in
if let JSON = response.result.value {
print("inside JSON result")
if let dict = JSON as? NSDictionary {
print("inside decoded JSON")
if let results = dict["results"] as? [NSDictionary] {
for result in results {
if let movieUrlString = result["poster_path"] as? String {
print(movieUrlString)
}
}
}
}
}
}
I have two Realm tables declared:
class Task: Object {
dynamic var taskID: String = ""
let taskAssignedTo = List<Contacts>()
}
class Contacts: Object {
dynamic var contactEmail: String = ""
dynamic var contactName: String = ""
}
Final goal is to convert the Task Realm object into JSON. The method I'm thinking of is:
Convert the object to a dictionary using a method within the class
func taskToDictionary() -> [String: AnyObject] {
return [
"taskID" : self.taskID,
"taskAssignedTo" : self.taskAssignedTo._rlmArray.count //Not sure how to get the array
]
}
Convert the resulting dictionary into JSON with SwiftyJSON
let taskObject = Task()
let newTaskJSON = JSON(taskObject.taskToDictionary())
Right now, this converts ok, but:
Is there a better way to do this?
How can I convert the RLMArray into an array for JSON conversion?
Managed to find the answer here:
Can I serialize a RealmObject to JSON or to NSDictionary in Realm for Swift?
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
var mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let objectClassName = prop.objectClassName {
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
if let object = nestedListObject._rlmArray[index] as? Object {
objects.append(object.toDictionary())
}
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
}
return mutabledic
}
}
Update for Xcode 7 & Swift 2:
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValuesForKeys(properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeysWithDictionary(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name)
}
}
return mutabledic
}
}
Update to Xcode 8 and Swift 3 :
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property]! {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase {
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as AnyObject
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
As i can't comment, #Eric
Based on #Eugene Teh answer
I had to do a specific treatment for date. Here is my code (swift 3)
I get the value first
if let value = self.value(forKey: props.name) {
if props.type == .date {
mutabledic[props.name] = (value as! Date).timeIntervalSince1970
//for using like the example, this should work
//mutabledic.setObject( (value as! Date).timeIntervalSince1970, forKey: prop.name as NSCopying)
}
[..]//other case
}
Swift 4.2 Xcode 11
This is how i solved the issue. To covert Realm Objects into JSON Array for sending to the Rest APIs
Requirement - SwiftyJSON
func getJsonArray(){
var dicArray = [Dictionary<String,AnyObject>]()
for item in cartsData! {
dicArray.append(item.toDictionary())
}
print(JSON(dicArray))
}
cartsData - var cartsData : Results<...>?
extension Object {
func toDictionary() -> [String:AnyObject] {
let properties = self.objectSchema.properties.map { $0.name }
var dicProps = [String:AnyObject]()
for (key, value) in self.dictionaryWithValues(forKeys: properties) {
//key = key.uppercased()
if let value = value as? ListBase {
dicProps[key] = value.toArray1() as AnyObject
} else if let value = value as? Object {
dicProps[key] = value.toDictionary() as AnyObject
} else {
dicProps[key] = value as AnyObject
}
}
return dicProps
}
}
extension ListBase {
func toArray1() -> [AnyObject] {
var _toArray = [AnyObject]()
for i in 0..<self._rlmArray.count {
let obj = unsafeBitCast(self._rlmArray[i], to: Object.self)
_toArray.append(obj.toDictionary() as AnyObject)
}
return _toArray
}
}