-1

this question is similar to Replace occurrences of NSNull in nested NSDictionary

In swift I am getting an error (I believe because of NSNull's) I don't really care if the NSNull becomes an empty string or a nil. I am just wanting to get the code to work.

I have a large data structure coming in from JSON as an NSDictionary. Then I am saving that to a temporary file. Here is the code:

var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary

let json = JSON(jsonResult)

if (json["errors"].array?.count > 0) {
                println("could not load stuff")
            } else {
                println("retrieving the stuff")

                let file = "file.txt"
                let file_path = NSTemporaryDirectory() + file
                let dict:NSDictionary = jsonResult
                let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)

                    if dict.writeToFile(file_path, atomically: true) {
                        let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)

                        //--- need to handle the NSNull junk here


                        if let dict = readDict {
                            println("Temp file created, here are the contents: \(dict)")
                        } else {
                            println("!!!Failed to READ the dictionary data back from disk.")
                        }
                    }
                    else {
                        println("!!!Failed to WRITE the dictionary to disk.")
                    }
                }

Here's an example of what jsonResult looks like

things = (
  {
                "one" = one;
                two = "<null>";
                "three" = three;
                "four" = "<null>";
                "five" = five;
                "six" = "six-6";
                seven = 7;
                eight = eight;
                nine = "<null>";
                ten = "<null>";
                eleven = "<null>";
                "twelve" = "<null>";
            },
Community
  • 1
  • 1
Brandon Sturgeon
  • 223
  • 4
  • 13
  • *"In swift I am getting an error (I believe because of NSNull's)"* – Why do you believe that? What does the JSON look like and what errors do you get? – Martin R May 04 '15 at 17:08
  • @MartinR Looking at the jsonResult, it looks like that is the problem. Is there a way to force everything to be a string? I know because of the writeToFile all the keys MUST be a string. I put an example of what jsonResult looks like into the main post. I was also getting a "fatal error: unexpectedly found nil while unwrapping an Optional value" a bit ago (I am no longer getting that for some reason) – Brandon Sturgeon May 04 '15 at 21:17

1 Answers1

1

UPDATE:

Problem: I have a very large amount of JSON (roughly 600kb as text) Within that JSON data there are nulls. The problem I was having is that when you NSJSONSerialization as NSDictionary, it converts the nulls into NSNull objects (it looks funky if you print this out because they appear as a string, this is wrong.

Solution: You need to have a "pruned" or "sanitized" dictionary. What this means is to throw out the key and value entirely. To do this, I added a sanitized_dict function. Here is the function:

func sanitize_dict(obj: AnyObject) -> AnyObject {

    if obj.isKindOfClass(NSDictionary) {

        var saveableObject = obj as! NSMutableDictionary

        for (key, value) in obj as! NSDictionary {

            if (value.isKindOfClass(NSNull)) {

                //println("Removing NSNull for: \(key)")

                saveableObject.removeObjectForKey(key)

            }

            if (value.isKindOfClass(NSArray)) {

                let tmpArray: (AnyObject) = sanitize_dict(value as! NSArray)

                saveableObject.setValue(tmpArray, forKey: key as! String)

            }

            if (value.isKindOfClass(NSDictionary)) {

                let tmpDict: (AnyObject) = sanitize_dict(value as! NSDictionary)

                saveableObject.setValue(tmpDict, forKey: key as! String)

            }

        }

        return saveableObject



    //--- because arrays are handled differently,

    //--- you basically need to do the same thing, but for an array

    //--- if the object is an array

    } else if obj.isKindOfClass(NSArray) {

        var saveableObject = [AnyObject]()

        for (index, ele) in enumerate(obj as! NSArray) {

            if (ele.isKindOfClass(NSNull)) {

                // simply don't add element to saveableobject and we're good

            }

            if (ele.isKindOfClass(NSArray)) {

                let tmpArray: (AnyObject) = sanitize_dict(ele as! NSArray)

                saveableObject.append(tmpArray)

            }

            if (ele.isKindOfClass(NSDictionary)) {

                let tmpDict: (AnyObject) = sanitize_dict(ele as! NSDictionary)

                saveableObject.append(tmpDict)

            }

        }

        return saveableObject

    }



    // this shouldn't happen, but makes code work

    var saveableObject = [AnyObject]()

    return saveableObject

}

So your other code needs to call that function, it should look something like this:

var err: NSError?

        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as! NSDictionary

        //--- right now jsonResult is not actual json, and actually has the NSNulls

        //--- get that result into the sanitized function above

        let saveableDict: (AnyObject) = self.sanitize_dict(jsonResult)

        let json = JSON(saveableDict)



        if (json["errors"].array?.count > 0) {

            println("!!!Failed to load.")

        } else {

            println("Load json successful. Attempting to save file...")



            //--- set up basic structure for reading/writing temp file

            let file = "file.txt"

            let file_path = NSTemporaryDirectory() + file

            let dict:NSDictionary = jsonResult

            let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)



                if dict.writeToFile(file_path, atomically: true) {

                    let readDict:NSDictionary? = NSDictionary(contentsOfFile: file_path)



                    if let dict = readDict {

                        println("Temp file created, here are the contents: \(dict)")

                    } else {

                        println("!!!Failed to READ the dictionary data back from disk.")

                    }

                }

                else {

                    println("!!!Failed to WRITE the dictionary to disk.")

                }

            }

Hope this helps somebody out there with a big JSON dataset and nulls. It is all about that sanitize function!

Brandon Sturgeon
  • 223
  • 4
  • 13