How to save an array as a json file in Swift?

前端 未结 6 1801
旧时难觅i
旧时难觅i 2020-12-04 11:33

I\'m new at swift and I\'m having trouble with this. so what i need to do is save this array as a json file in the document folder of the iphone.

var levels          


        
相关标签:
6条回答
  • 2020-12-04 11:55

    In Swift 4 this is already built-in with JSONEncoder.

    let pathDirectory = getDocumentsDirectory()
    try? FileManager().createDirectory(at: pathDirectory, withIntermediateDirectories: true)
    let filePath = pathDirectory.appendingPathComponent("levels.json")
    
    let levels = ["unlocked", "locked", "locked"]
    let json = try? JSONEncoder().encode(levels)
    
    do {
         try json!.write(to: filePath)
    } catch {
        print("Failed to write JSON data: \(error.localizedDescription)")
    }
    
    func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
    

    The object you're trying to encode must conform to the Encodable protocol.

    Read Apple's official guide on how to extend existing objects to be encodable.

    0 讨论(0)
  • 2020-12-04 12:00

    Here is generic Swift solution

    I have created generic class which allows to do it easily

    //
    //  OfflineManager.swift
    // 
    //
    //  Created by Prashant on 01/05/18.
    //  Copyright © 2018 Prashant. All rights reserved.
    //
    
    import UIKit
    
    class OfflineManager: NSObject {
    
        static let sharedManager = OfflineManager()
        let LocalServiceCacheDownloadDir        = "LocalData"
    
        // Replace case as your naming 
    
        enum WSCacheKeys {
            case CampignList . 
            case CampignDetail(id:String)
            case ScreenShotList
    
            var value:String {
                switch self {
                case .CampignList:
                  return  "CampignList"
                case .CampignDetail(let id):
                    return id
                case .ScreenShotList :
                    return "ScreenShotList"
                }
    
            }
        }
    
        func getBaseForCacheLocal(with fileName:String) -> String? {
    
            let filePath = FileManager.default.getDocumentPath(forItemName: self.LocalServiceCacheDownloadDir)
            if FileManager.default.directoryExists(atPath: filePath) {
                return filePath.stringByAppendingPathComponent(fileName)
            } else {
                if  FileManager.default.createDirectory(withFolderName: self.LocalServiceCacheDownloadDir) {
                    return filePath.stringByAppendingPathComponent(fileName)
                }
            }
            return nil
        }
    
    
    
        //------------------------------------------------------------
    
        @discardableResult
        func cacheDataToLocal<T>(with Object:T,to key:WSCacheKeys) -> Bool {
            let success = NSKeyedArchiver.archiveRootObject(Object, toFile: getBaseForCacheLocal(with: key.value)!)
            if success {
                print( "Local Data Cached\(String(describing: getBaseForCacheLocal(with: key.value)))")
            } else {
                print("Error")
            }
    
            return success
    
        }
    
        //------------------------------------------------------------
    
        func loadCachedDataFromLocal<T>(with key:WSCacheKeys ) -> T? {
            return NSKeyedUnarchiver.unarchiveObject(withFile: getBaseForCacheLocal(with: key.value)!) as? T
        }
    
    
        //------------------------------------------------------------
    
    
        func removeAllCacheDirs () {
            do {
                try FileManager.default.removeItem(atPath: self.getBaseForCacheLocal(with: "")!)
    
            } catch {
                print("error in remove dir \(error.localizedDescription)")
            }
    
        }
    
        //--------------------------------------------------------------------------------
    
    
    }
    

    Here is some helper methods of extension FileManager

    public var getDocumentDirectoryPath: String {
        let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        return documentDirectory
    }
    
    public func getDocumentPath(forItemName name: String)-> String {
        return getDocumentDirectoryPath.stringByAppendingPathComponent(name)
    }
    
    public func directoryExists(atPath filePath: String)-> Bool {
        var isDir = ObjCBool(true)
        return FileManager.default.fileExists(atPath: filePath, isDirectory: &isDir )
    }
    
    public func createDirectory(withFolderName name: String)-> Bool {
        let finalPath = getDocumentDirectoryPath.stringByAppendingPathComponent(name)
        return createDirectory(atPath: finalPath)
    }
    

    Here Is String extension's method

    public func stringByAppendingPathComponent(_ path: String) -> String {
        let fileUrl = URL.init(fileURLWithPath: self)
        let filePath = fileUrl.appendingPathComponent(path).path
        return filePath
    }
    

    How to use it ?

    To save

       OfflineManager.sharedManager.cacheDataToLocal(with: object as! [String:Any], to: .CampignList)
    

    To read data

        DispatchQueue.global().async {
            // GET OFFLINE DATA
            if let object:[String:Any] = OfflineManager.sharedManager.loadCachedDataFromLocal(with: .CampignList) {
                do {
                    let data = try  JSONSerialization.data(withJSONObject: object, options: [])
                    let object = try CampaignListResponse.init(data: data)
                    self.arrCampignList = object.data ?? []
                    DispatchQueue.main.async {
                        self.tableVIew.reloadData()
                    }
                } catch {
                }
            }
          }
    

    Note: You can define your own WSCacheKeys for type of your json like i am fetching some campaign list

    0 讨论(0)
  • #1. Save a Swift Array as a json file

    The following Swift 3 / iOS 10 code shows how to transform an Array instance into json data and save it into a json file located in an iPhone's document directory using FileManager and JSONSerialization:

    func saveToJsonFile() {
        // Get the url of Persons.json in document directory
        guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let fileUrl = documentDirectoryUrl.appendingPathComponent("Persons.json")
    
        let personArray =  [["person": ["name": "Dani", "age": "24"]], ["person": ["name": "ray", "age": "70"]]]
    
        // Transform array into data and save it into file
        do {
            let data = try JSONSerialization.data(withJSONObject: personArray, options: [])
            try data.write(to: fileUrl, options: [])
        } catch {
            print(error)
        }
    }
    
    /*
     Content of Persons.json file after operation:
     [{"person":{"name":"Dani","age":"24"}},{"person":{"name":"ray","age":"70"}}]
    */
    

    As an alternative, you can implement the following code that use streams:

    func saveToJsonFile() {
        // Get the url of Persons.json in document directory
        guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let fileUrl = documentDirectoryUrl.appendingPathComponent("Persons.json")
    
        let personArray =  [["person": ["name": "Dani", "age": "24"]], ["person": ["name": "ray", "age": "70"]]]
    
        // Create a write-only stream
        guard let stream = OutputStream(toFileAtPath: fileUrl.path, append: false) else { return }
        stream.open()
        defer {
            stream.close()
        }
    
        // Transform array into data and save it into file
        var error: NSError?
        JSONSerialization.writeJSONObject(personArray, to: stream, options: [], error: &error)
    
        // Handle error
        if let error = error {
            print(error)
        }
    }
    
    /*
     Content of Persons.json file after operation:
     [{"person":{"name":"Dani","age":"24"}},{"person":{"name":"ray","age":"70"}}]
    */
    

    #2. Get a Swift Array from a json file

    The following Swift 3 / iOS 10 code shows how to get data from a json file located in an iPhone's document directory and transform it into an Array instance using FileManager and JSONSerialization:

    /*
     Content of Persons.json file:
     [{"person":{"name":"Dani","age":"24"}},{"person":{"name":"ray","age":"70"}}]
    */
    
    func retrieveFromJsonFile() {
        // Get the url of Persons.json in document directory
        guard let documentsDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let fileUrl = documentsDirectoryUrl.appendingPathComponent("Persons.json")
    
        // Read data from .json file and transform data into an array
        do {
            let data = try Data(contentsOf: fileUrl, options: [])
            guard let personArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: [String: String]]] else { return }
            print(personArray) // prints [["person": ["name": "Dani", "age": "24"]], ["person": ["name": "ray", "age": "70"]]]
        } catch {
            print(error)
        }
    }
    

    As an alternative, you can implement the following code that use streams:

    /*
     Content of Persons.json file:
     [{"person":{"name":"Dani","age":"24"}},{"person":{"name":"ray","age":"70"}}]
    */
    
    func retrieveFromJsonFile() {
        // Get the url of Persons.json in document directory
        guard let documentsDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let fileUrl = documentsDirectoryUrl.appendingPathComponent("Persons.json")
    
        // Create a read-only stream
        guard let stream = InputStream(url: fileUrl) else { return }
        stream.open()
        defer {
            stream.close()
        }
    
        // Read data from .json file and transform data into an array
        do {
            guard let personArray = try JSONSerialization.jsonObject(with: stream, options: []) as? [[String: [String: String]]] else { return }
            print(personArray) // prints [["person": ["name": "Dani", "age": "24"]], ["person": ["name": "ray", "age": "70"]]]
        } catch {
            print(error)
        }
    }
    

    The Playground located in the Github's Save-and-read-JSON-from-Playground repo shows how to save a Swift Array into a json file and how to read a json file and get a Swift Array from it.

    0 讨论(0)
  • 2020-12-04 12:04

    Here is Isuru's answer in Swift 4.2. This works in a playground:

    let documentsDirectoryPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
    let documentsDirectoryPath = NSURL(string: documentsDirectoryPathString)!
    
    let jsonFilePath = documentsDirectoryPath.appendingPathComponent("test.json")
    let fileManager = FileManager.default
    var isDirectory: ObjCBool = false
    
    // creating a .json file in the Documents folder
    if !fileManager.fileExists(atPath: (jsonFilePath?.absoluteString)!, isDirectory: &isDirectory) {
        let created = fileManager.createFile(atPath: jsonFilePath!.absoluteString, contents: nil, attributes: nil)
        if created {
            print("File created ")
        } else {
            print("Couldn't create file for some reason")
        }
    } else {
        print("File already exists")
    }
    
    // creating an array of test data
    var numbers = [String]()
    for i in 0..<100 {
        numbers.append("Test\(i)")
    }
    
    // creating JSON out of the above array
    var jsonData: NSData!
    do {
        jsonData = try JSONSerialization.data(withJSONObject: numbers, options: JSONSerialization.WritingOptions()) as NSData
        let jsonString = String(data: jsonData as Data, encoding: String.Encoding.utf8)
        print(jsonString as Any)
    } catch let error as NSError {
        print("Array to JSON conversion failed: \(error.localizedDescription)")
    }
    
    // Write that JSON to the file created earlier
    //    let jsonFilePath = documentsDirectoryPath.appendingPathComponent("test.json")
    do {
        let file = try FileHandle(forWritingTo: jsonFilePath!)
        file.write(jsonData as Data)
        print("JSON data was written to teh file successfully!")
    } catch let error as NSError {
        print("Couldn't write to file: \(error.localizedDescription)")
    }
    
    0 讨论(0)
  • 2020-12-04 12:07

    If you're like me who doesn't like to use a whole new third-party framework just for a trivial thing like this, here's my solution in vanilla Swift. From creating a .json file in the Documents folder to writing JSON in to it.

    let documentsDirectoryPathString = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first!
    let documentsDirectoryPath = NSURL(string: documentsDirectoryPathString)!
    
    let jsonFilePath = documentsDirectoryPath.URLByAppendingPathComponent("test.json")
    let fileManager = NSFileManager.defaultManager()
    var isDirectory: ObjCBool = false
    
    // creating a .json file in the Documents folder
    if !fileManager.fileExistsAtPath(jsonFilePath.absoluteString, isDirectory: &isDirectory) {
        let created = fileManager.createFileAtPath(jsonFilePath.absoluteString, contents: nil, attributes: nil)
        if created {
            print("File created ")
        } else {
            print("Couldn't create file for some reason")
        }
    } else {
        print("File already exists")
    }
    
    // creating an array of test data
    var numbers = [String]()
    for var i = 0; i < 100; i++ {
        numbers.append("Test\(i)")
    }
    
    // creating JSON out of the above array
    var jsonData: NSData!
    do {
        jsonData = try NSJSONSerialization.dataWithJSONObject(numbers, options: NSJSONWritingOptions())
        let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)
        print(jsonString)
    } catch let error as NSError {
        print("Array to JSON conversion failed: \(error.localizedDescription)")
    }
    
    // Write that JSON to the file created earlier
    let jsonFilePath = documentsDirectoryPath.URLByAppendingPathComponent("test.json")
    do {
        let file = try NSFileHandle(forWritingToURL: jsonFilePath)
        file.writeData(jsonData)
        print("JSON data was written to teh file successfully!")
    } catch let error as NSError {
        print("Couldn't write to file: \(error.localizedDescription)")
    }
    
    0 讨论(0)
  • 2020-12-04 12:16

    I recommend that you use SwiftyJSON framework. Study its documentation and in addition learn how to write strings to files (hint: NSFileHandle)

    Something like the code below, but you really need to study both SwiftyJSON and NSFileHandle to learn how to both serialize JSON data to a file and parse JSON data from a file

    let levels = ["unlocked", "locked", "locked"]
    let json = JSON(levels)
    let str = json.description
    let data = str.dataUsingEncoding(NSUTF8StringEncoding)!
    if let file = NSFileHandle(forWritingAtPath:path) {
        file.writeData(data)
    } 
    
    0 讨论(0)
提交回复
热议问题