如何在 Swift 中将数组保存为 json 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28768015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to save an array as a json file in Swift?
提问by elpita
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.
我是 swift 的新手,我遇到了这个问题。所以我需要做的是将这个数组保存为 iphone 的文档文件夹中的 json 文件。
var levels = ["unlocked", "locked", "locked"]
and then later on be able to read it back into another array. Could someone please tell me how to do this? or provided with the exact code to accomplish this.
然后稍后能够将其读回另一个数组。有人可以告诉我怎么做吗?或提供完成此操作的确切代码。
EDITED: I found one example of this. This is how they set up the data:
编辑:我发现了一个例子。这是他们设置数据的方式:
"[ {"person": {"name":"Dani","age":"24"}}, {"person": {"name":"ray","age":"70"}} ]"
and the you can access it this way:
您可以通过以下方式访问它:
if let item = json[0]
{ if let person = item["person"]
{ if let age = person["age"]
{ println(age) } } }
But I need to be able to do the same but from a file that is saved on the document folder.
但是我需要能够从保存在文档文件夹中的文件中执行相同的操作。
采纳答案by Teemu Kurppa
I recommend that you use SwiftyJSONframework. Study its documentation and in addition learn how to write strings to files (hint: NSFileHandle)
我建议您使用SwiftyJSON框架。究其文档和除学习如何将字符串写入到文件(提示: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
类似于下面的代码,但您确实需要研究 SwiftyJSON 和 NSFileHandle 以了解如何将 JSON 数据序列化为文件并从文件中解析 JSON 数据
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)
}
回答by Isuru
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.
如果你像我一样不喜欢使用全新的第三方框架来处理这样的小事,这是我在 vanilla Swift 中的解决方案。从在 Documents 文件夹中创建 .json 文件到将 JSON 写入其中。
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)")
}
回答by Imanou Petit
#1. Save a Swift Arrayas a json file
#1. 将 Swift 保存Array为 json 文件
The following Swift 3 / iOS 10 code shows how to transform an Arrayinstance into json data and save it into a json file located in an iPhone's document directory using FileManagerand JSONSerialization:
下面的斯威夫特3 / iOS的10码展示了如何改造一个Array实例为JSON数据并将其保存到位于使用iPhone的文档目录中的一个JSON文件FileManager和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 Arrayfrom a json file
#2. Array从 json 文件中获取 Swift
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 Arrayinstance using FileManagerand JSONSerialization:
以下 Swift 3 / iOS 10 代码显示了如何从位于 iPhone 文档目录中的 json 文件中获取数据,并Array使用FileManagerand将其转换为实例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-Playgroundrepo shows how to save a Swift Arrayinto a json file and how to read a json file and get a Swift Arrayfrom it.
位于 Github 的Save-and-read-JSON-from-Playground 存储库中的 Playground展示了如何将 Swift 保存Array到 json 文件以及如何读取 json 文件并从中获取 Swift Array。
回答by Mastergalen
In Swift 4 this is already built-in with JSONEncoder.
在 Swift 4 中,这已经内置于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 Encodableprotocol.
您尝试编码的对象必须符合Encodable协议。
Read Apple's official guideon how to extend existing objects to be encodable.
阅读Apple 的官方指南,了解如何将现有对象扩展为可编码。
回答by Prashant Tukadiya
Here is generic Swift solution
这是通用的 Swift 解决方案
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
这里有一些辅助方法 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 WSCacheKeysfor type of your json like i am fetching some campaign list
注意:您可以定义自己WSCacheKeys的 json 类型,就像我正在获取一些广告系列列表一样
回答by Brody Higby
Here is Isuru's answer in Swift 4.2. This works in a playground:
这是 Isuru 在Swift 4.2 中的回答。这适用于操场:
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)")
}

