Как сохранить массив в виде json файла в Swift?
Я новичок в быстроте, и у меня проблемы с этим. так что мне нужно сделать, это сохранить этот массив как json файл в папке документа iphone.
var levels = ["unlocked", "locked", "locked"]
а затем позже сможет прочитать его обратно в другой массив. Может кто-нибудь, пожалуйста, скажите мне, как это сделать? или для получения точного кода.
EDITED: Я нашел один пример этого. Вот как они настраивают данные:
"[ {"person": {"name":"Dani","age":"24"}}, {"person": {"name":"ray","age":"70"}} ]"
и вы можете получить к нему доступ таким образом:
if let item = json[0]
{ if let person = item["person"]
{ if let age = person["age"]
{ println(age) } } }
Но мне нужно иметь возможность делать то же самое, но из файла, который сохраняется в папке документа.
Ответы
Ответ 1
Я рекомендую вам использовать среду SwiftyJSON. Изучите его документацию и дополнительно научитесь писать строки в файлы (подсказка: NSFileHandle
)
Что-то вроде кода ниже, но вам действительно нужно изучить 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)
}
Ответ 2
Если вы похожи на меня, который не любит использовать совершенно новую стороннюю структуру только для такой тривиальной вещи, вот мое решение в ваниле Свифт. От создания файла.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)")
}
Ответ 3
# 1. Сохранить Swift Array
как json файл
Следующий код Swift 3/iOS 10 показывает, как преобразовать экземпляр Array
в данные json и сохранить его в файл json, расположенный в каталоге документов iPhone, используя 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"}}]
*/
В качестве альтернативы вы можете реализовать следующий код, который использует потоки:
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. Получить Swift Array
из json файла
Следующий код Swift 3/iOS 10 показывает, как получить данные из json файла, расположенного в каталоге документов iPhone, и преобразовать его в экземпляр Array
с помощью FileManager
и 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)
}
}
В качестве альтернативы вы можете реализовать следующий код, который использует потоки:
/*
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)
}
}
Игровая площадка, расположенная в репозитории Github Save-and-read-JSON-from-Playground, показывает, как сохранить Swift Array
в json файл и как прочитать json файл и получить из него Swift Array
.
Ответ 4
В 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]
}
Объект, который вы пытаетесь кодировать, должен соответствовать протоколу Encodable
.
Прочитайте официальное руководство Apple о том, как расширить существующие объекты для кодирования.
Ответ 5
Вот общее решение Swift
Я создал общий класс, который позволяет сделать это легко
//
// 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)")
}
}
//--------------------------------------------------------------------------------
}
Вот некоторые вспомогательные методы 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)
}
Здесь используется метод расширения строк
public func stringByAppendingPathComponent(_ path: String) -> String {
let fileUrl = URL.init(fileURLWithPath: self)
let filePath = fileUrl.appendingPathComponent(path).path
return filePath
}
Как это использовать?
Сохранить
OfflineManager.sharedManager.cacheDataToLocal(with: object as! [String:Any], to: .CampignList)
Для чтения данных
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 {
}
}
}
Примечание. Вы можете определить свои собственные WSCacheKeys
для типа вашего json, так как я WSCacheKeys
список кампаний
Ответ 6
Вот ответ Исуру в 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)")
}