2017-02-17 3 views
1

Я пытаюсь прочитать JSON-файл из myFile.json в Bundle, изменить некоторые элементы и сохранить его в каталоге документа в виде файла JSON. Я думал, что это будет простой способ сохранить данные. Впоследствии я намерен читать и писать в каталог документов. Следующий код показывает, что я сделал и сильно комментирует. Кажется, мне не хватает какого-то существенного шага, потому что ожидаемые конверсии JSON не соответствуют спецификации JSON. Я открыт для предложений о том, как мне пройти тестирование на игровой площадке. Код основан наПолучение неожиданного преобразования из JSON в словарь и обратно в JSON

Convert Dictionary to JSON in Swift

import UIKit 

/* Trying to read a json file from myFile.json in Bundle, modify some elemnts and store it 
in the document directory as a json file. Subsequently, intent to read and write to document directory 

myFile.json consistes of 

{ 
"record": {"id": "A1234", "customer": "Customer-1"} 
} 

*/ 


typealias MyRecord = [String: AnyObject] 
var json:MyRecord! 
let fileName = "myFile" 
var dictionary = MyRecord() 

func loadJsonFromBundle (forFilename fileName: String) -> MyRecord { 

    if let url = Bundle.main.url(forResource: fileName, withExtension: "json") { 
     if let data = NSData(contentsOf: url) { 
      do { 
       let dictionary = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments) as? [String:Any] 
       print("dictionary = \(dictionary!)") 
       /* displays 
       dictionary = ["record": { 
       customer = "Customer-1"; 
       id = A1234; 
       }] 
       */ 

       return dictionary! as MyRecord 
      } catch { 
       print("Error!! Unable to parse \(fileName).json") 
      } 
     } 
     print("Error!! Unable to load \(fileName).json") 
    } 

    return [:] 
} 

func loadJsonFromDocument (forFilename fileName: String) -> MyRecord { 

    let docDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 
    if let url = docDirectory?.appendingPathComponent(fileName).appendingPathExtension("json") { 
     if let data = NSData(contentsOf: url) { 
      do { 
       let dictionary = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments) as? [String:Any] 
       print("dictionary = \(dictionary!)") 
       return dictionary! as MyRecord 
      } catch { 
       print("Error!! Unable to parse \(fileName).json") 
      } 
     } 
     print("Error!! Unable to load \(fileName).json") 
    } 

    return [:] 
} 


func saveJsonToFile (_ fileName:String, outString: String) -> URL { 
    let docDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 
    if let fileURL = docDirectory?.appendingPathComponent(fileName).appendingPathExtension("json") { 
     print("fileURL = \(fileURL)") 
     // Write to a file on disk 

     do { 
      try outString.write(to: fileURL, atomically: true, encoding: .utf8) 
     } catch { 
      print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription) 
     } 
     return fileURL 
    } 
    return URL(string: "")! 
} 

let sq = "\"" 
func q(_ x:String) -> String { 
    return "\(sq)\(x)\(sq)" 
} 


dictionary = loadJsonFromBundle (forFilename: fileName) 
var a = dictionary["record"] as? [String:String] 
a?["customer"] = "newName" 
var dict = MyRecord() 
dict["record"] = a as AnyObject? 
print(dict) 

/* prints: 

["record": { 
customer = newName; 
id = A1234; 
}] 

*/ 

// https://stackoverflow.com/questions/29625133/convert-dictionary-to-json-in-swift/29628000#29628000 
do { 
    let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) 
    // here "jsonData" is the dictionary encoded in JSON data 

    let decoded = try JSONSerialization.jsonObject(with: jsonData, options: []) 
    // here "decoded" is of type `Any`, decoded from JSON data 

    // you can now cast it with the right type 
    if let dictFromJSON = decoded as? [String:Any] { 

     // need to save dictFromJson to a file in document directory 
     // saveJsonToFile is expecting a String for the json argument 
     // I converted dictFromJson to a string so I can save it 
     var outString = String(describing: dictFromJSON) 

     print("outString = \(outString)") 

     /* Notice that the internal structure is not quoted and there are semi-colons 

     outString = ["record": { 
     customer = newName; 
     id = A1234; 
     }] 

     */ 
     outString = outString.replacingOccurrences(of: "[", with: "{") 
     outString = outString.replacingOccurrences(of: "]", with: "}") 



     let url = saveJsonToFile("newFile", outString: String(describing: outString)) 
     print(url) 
     /* Resulting File looks like this: 

     {"record": { 
     customer = newName; 
     id = A1234; 
     }} 

     Question: Why were the braces swapped with brackets. The internal elements 
     were not quoted. 

     */ 

     // Will try to read back the json string from document directory 
     dictionary = loadJsonFromDocument(forFilename: fileName) 
     // results in ERROR (Unable to load myFile.json 


     a = dictionary["record"] as? [String:String] 
     a?["customer"] = "newName" 
     dict = MyRecord() 
     dict["record"] = a as AnyObject? 
     print(dict) 

    } 
} catch { 
    print(error.localizedDescription) 
} 
+0

вы должны попробовать [String: Any], а не [String: AnyObject]. –

ответ

1

Issue указываемого vadian правильно, что вы храните словарь объекта, но вместо преобразования Data в String, а затем написать, что String вы можете напрямую писать Data в DocumentDirectory.

Так что я изменил вашу функцию saveJsonToFile, которая принимает Data как второй аргумент вместо String.

func saveJsonToFile (_ fileName:String, jsonData: Data) -> URL { 
    let docDirectory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 
    if let fileURL = docDirectory?.appendingPathComponent(fileName).appendingPathExtension("json") { 
     print("fileURL = \(fileURL)") 
     // Write to a file on disk 

     do { 
      try jsonData.write(to: fileURL) 
     } catch { 
      print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription) 
     } 
     return fileURL 
    } 
    return URL(string: "")! 
} 

Теперь просто вызовите эту функцию после того, как вы измените свой результат json и преобразуете его в данные.

do { 
    let jsonData = try JSONSerialization.data(withJSONObject: dict, options: []) 
    let url = saveJsonToFile("newFile", jsonData: jsonData) 
    print(url) 
} catch { 
    print(error.localizedDescription) 
} 
1

Проблема в том, что вы сохраните объект словаря в файл, а не кодированном формате JSON.

Используйте только JSONSerialization от объекта к данным и не пропускайте .prettyprinted.

do { 
    let jsonData = try JSONSerialization.data(withJSONObject: dict, options:[]) 
    // here "jsonData" is the dictionary encoded in JSON data 

    let outString = String(data:jsonData, encoding:.utf8) 

    print("outString = \(outString)") 
    let url = saveJsonToFile("newFile", outString: outString) 
    print(url) 
    } 
} catch { 
    print(error.localizedDescription) 
} 
+0

Vadian - Спасибо за быстрый ответ и знания. Ответ должен был быть мне понятен, но он просто не зарегистрировался. –