Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save/retrieve dictionary from file using SwiftyJSON

I'm trying to make the conversion from Objc to swift and have had better days.

I have a class with a dictionary:

 collaborationDictionary:[String:Set<String>]

I am trying to write/read this dictionary to/from a file and just can't quite seem to make it work. I have to save the dictionary using the following JSON structure and I have to use SwiftyJSON.

 { "Collaborations" : {
          "5604" : [
              "whiteboard.png",
              "VID_20161123_135117.3gp",
              "Photo_0.jpeg"]
          "5603" : [
              "VID_20161123_135117.3gp"],
          "5537" : [
              "Screenshot_20151212-132454.png",
              "VID_20161202_083205.3gp",
              "VID_20161123_135117.3gp",
              "Photo_0.jpeg",
              "Screenshot_20151212-132428.png",
              "Screenshot_20151212-132520.png",
              "IMG_20161017_132105.jpg",
              "whiteboard.png"]}
 }

I don't have any real problem with finding/retrieving the file or writing the file. I just can't quite figure out how to manually load SwiftyJSON. I need to have a JSON object called "Collaborations" at the top. It needs to contain a dictionary of collaboration IDs (5604, 5603...). Each collaboration contains an array of string (filenames). I'm including the code I'm using to read/write the file but I need help with the SwiftyJSON library.

This is the member data member I'm using to store the above data:

These are the functions I need to finish:

     private var collaborationDictionary:[String:Set<String>] = [:]


  func getUploadedFileSet() {
    collaborationDictionary = [:]
    let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
    let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
    let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)

    if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
        do {
            let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
            let json = JSON(data: data)

            // ************************************************
            // NEED HELP START
            // NOW WHAT????  What is the SwiftyJSON code

            ?????????????????????????                

            // NEED HELP END
            // ************************************************

        } catch let error {
            print(error.localizedDescription)
        }
    }
 }

  func saveUploadedFilesSet() {        
    let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
    let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
    let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)

    do {
        let dirExists = FileManager.default.fileExists(atPath: (appURL?.absoluteString)!)
        if !dirExists {
            try FileManager.default.createDirectory(atPath: (appURL?.absoluteString)!, withIntermediateDirectories: false, attributes: nil)
        }

        // ************************************************
        // NEED HELP START
            // NOW WHAT????  What is the SwiftyJSON code

            ?????????????????????????                

        // NEED HELP END
        // ************************************************

        // Write to file code - haven't written it yet but that should be easy          

    } catch let error as NSError {
        print(error.localizedDescription);
    }
 }

Any direction would be greatly appreciated. Thanks!

EDIT

I was able to figure out how to load the supplied JSON structure from file. Here is the code:

 func getUploadedFileSet() {
    let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
    let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
    let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)

    if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
        do {
            let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
            let json = JSON(data: data)
            if json != nil {
                for (key, subJson) in json[kCollaborations] {
                    let stringArray:[String] = subJson.arrayValue.map { $0.string! }
                    let stringSet = Set(stringArray)
                    collaborationDictionary.updateValue(stringSet, forKey: key)
                }
            } else {
                print("Could not get json from file, make sure that file contains valid json.")
            }
        } catch let error {
            print(error.localizedDescription)
        }
    }

I still haven't figured out how to save the collaborationDictionary object to file. My biggest problem is figuring out how to put in the "Collaborations" key. Any ideas?

like image 472
JustLearningAgain Avatar asked Dec 14 '16 14:12

JustLearningAgain


2 Answers

I finally got this to work. The biggest problem was that I couldn't convert collaborationDictionary to JSON. I finally had to convert it to a dictionary of arrays vs dictionary of sets. Here are the 2 methods:

     // **************************************************************************
func getUploadedFileSet() {
    let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
    let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
    let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)

    if FileManager.default.fileExists(atPath: (jsonFileURL?.absoluteString)!) {
        do {
            let data = try Data(contentsOf: jsonFileURL!, options: .alwaysMapped)
            let json = JSON(data: data)
            if json != nil {
                for (key, subJson) in json[kCollaborations] {
                    let stringArray:[String] = subJson.arrayValue.map { $0.string! }
                    let stringSet = Set(stringArray)
                    collaborationDictionary.updateValue(stringSet, forKey: key)
                }
            } else {
                print("Could not get json from file, make sure that file contains valid json.")
            }
        } catch let error {
            print(error.localizedDescription)
        }
    }
}

// **************************************************************************
func saveUploadedFilesSet() {
    let documentsURL = URL(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
    let appURL = documentsURL?.appendingPathComponent(APP_DISTINGUISHED_NAME)
    let jsonFileURL = appURL?.appendingPathComponent(UPLOADED_ITEMS_DB_JSON)
    let adjustedJSONFileURL = URL(fileURLWithPath:(jsonFileURL?.absoluteString)!)

    do {
        let dirExists = FileManager.default.fileExists(atPath: (appURL?.absoluteString)!)
        if !dirExists {
            try FileManager.default.createDirectory(atPath: (appURL?.absoluteString)!, withIntermediateDirectories: false, attributes: nil)
        }

        // Convert set elements to arrays
        var convertedCollaborationDictionary: [String:[String]] = [:]
        for (sessionID, fileNameSet) in collaborationDictionary {
            let array = Array(fileNameSet)
            convertedCollaborationDictionary.updateValue(array, forKey: sessionID)
        }
        let json: JSON = JSON(convertedCollaborationDictionary)
        let fullJSON: JSON = [kCollaborations:json.object]
        let data = try fullJSON.rawData()
        try data.write(to: adjustedJSONFileURL, options: .atomic)

    } catch let error as NSError {
        print(error.localizedDescription);
    }
}
like image 79
JustLearningAgain Avatar answered Nov 20 '22 18:11

JustLearningAgain


If you dig into the source, SwiftyJSON wraps JSONSerialization, which can both be initialized and converted back to Data which is knows how to read and write itself from disk:

  func readJSON() -> JSON? {
      guard let url = Bundle.main.url(forResource: "data", withExtension: "json"),
            let data = try? Data(contentsOf: url) else {
          return nil
      }
      return JSON(data: data)
  }

  func write(json: JSON, to url: URL) throws {
      let data = try json.rawData()
      try data.write(to: url)
  }

Note that you can load your static data from anywhere including your Bundle, but you can only write to the sandbox (ie the Documents directory). You may wish to copy from your Bundle to the documents directory on first run if you are planning on reading/writing to the same file.

Also your sample JSON is bad (lint it). You need a comma after "Photo_0.jpeg"]

like image 2
Josh Homann Avatar answered Nov 20 '22 20:11

Josh Homann