Чтение в файле JSON с помощью Swift

135

Я действительно борюсь с попыткой прочитать файл JSON в Swift, чтобы я мог поиграть с ним. Я потратил большую часть 2-х дней на повторный поиск и пробую разные методы, но пока не повезло, поэтому я подписался на StackOverFlow, чтобы узнать, может ли кто-нибудь указать мне в правильном направлении.....

Мой JSON файл называется test.json и содержит следующее:

{
  "person":[
     {
       "name": "Bob",
       "age": "16",
       "employed": "No"
     },
     {
       "name": "Vinny",
       "age": "56",
       "employed": "Yes"
     }
  ]
}    

Файл хранится в документах напрямую, и я обращаюсь к нему с помощью следующего кода:

let file = "test.json"
let dirs : String[] = NSSearchPathForDirectoriesInDomains(
                                                          NSSearchpathDirectory.DocumentDirectory,
                                                          NSSearchPathDomainMask.AllDomainMask,
                                                          true) as String[]

if (dirs != nil) {
    let directories: String[] = dirs
    let dir = directories[0]
    let path = dir.stringByAppendingPathComponent(file)
}

var jsonData = NSData(contentsOfFile:path, options: nil, error: nil)
println("jsonData \(jsonData)" // This prints what looks to be JSON encoded data.

var jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: nil) as? NSDictionary

println("jsonDict \(jsonDict)") - This prints nil..... 

Если кто-то может просто дать мне толчок в правильном направлении, как я могу де-сериализовать JSON файл и поместить его в доступный объект Swift, я буду бесконечно благодарен!

С уважением,

Krivvenz.

  • 1
    используйте параметр ошибки ...
  • 2
    Пожалуйста, опубликуйте актуальный, скомпилированный код. Как теперь, path виден только if объем, и неразрешенным , когда вы используете его в NSData(contentsOfFile, options, error) ; у вас также есть опечатки в именах enum.
Показать ещё 1 комментарий
Теги:
xcode
nsjsonserialization
ios8

21 ответ

217
Лучший ответ

Следуйте приведенному ниже коду:

if let path = NSBundle.mainBundle().pathForResource("test", ofType: "json")
{
    if let jsonData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)
    {
        if let jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary
        {
            if let persons : NSArray = jsonResult["person"] as? NSArray
            {
                // Do stuff
            }
        }
     }
}

Массив "people" будет содержать все данные для ключевого лица. Итерируйте проходы, чтобы получить его.

Swift 4.0:

if let path = Bundle.main.path(forResource: "test", ofType: "json") {
    do {
          let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
          let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
          if let jsonResult = jsonResult as? Dictionary<String, AnyObject>, let person = jsonResult["person"] as? [Any] {
                    // do stuff
          }
      } catch {
           // handle error
      }
}
  • 1
    Вот код в SWIFT
  • 1
    Было бы более полезно, если бы вы объяснили, почему / как это решает проблему, описанную в вопросе, вместо того, чтобы просто представлять кучу кода.
Показать ещё 9 комментариев
126

Если кто-то ищет SwiftyJSON Ответ:
Обновить:
Для Swift 3/4:

if let path = Bundle.main.path(forResource: "assets/test", ofType: "json") {
    do {
        let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
        let jsonObj = try JSON(data: data)
        print("jsonData:\(jsonObj)")
    } catch let error {
        print("parse error: \(error.localizedDescription)")
    }
} else {
    print("Invalid filename/path.")
}
  • 2
    это превратило меня в swiftyJSON и Карфаген! Спасибо :)
  • 0
    я использовал его только для того, чтобы обнаружить, что в нем отсутствует сопоставление объектов, в следующий раз я попробую другую библиотеку
Показать ещё 4 комментария
56

Swift 4 с использованием Decodable

struct ResponseData: Decodable {
    var person: [Person]
}
struct Person : Decodable {
    var name: String
    var age: String
    var employed: String
}

func loadJson(filename fileName: String) -> [Person]? {
    if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
        do {
            let data = try Data(contentsOf: url)
            let decoder = JSONDecoder()
            let jsonData = try decoder.decode(ResponseData.self, from: data)
            return jsonData.person
        } catch {
            print("error:\(error)")
        }
    }
    return nil
}

Swift 3

func loadJson(filename fileName: String) -> [String: AnyObject]? {
    if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
        do {
            let data = try Data(contentsOf: url)
            let object = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
            if let dictionary = object as? [String: AnyObject] {
                return dictionary
            }
        } catch {
            print("Error!! Unable to parse  \(fileName).json")
        }
    }
    return nil
}
  • 7
    Это должно быть перенесено в новую функцию документации или помечено как правильный ответ.
  • 0
    @ Джаррид, я согласен !!!
23

Xcode 8 Swift 3 прочитайте json из файла обновления:

    if let path = Bundle.main.path(forResource: "userDatabseFakeData", ofType: "json") {
        do {
            let jsonData = try NSData(contentsOfFile: path, options: NSData.ReadingOptions.mappedIfSafe)
            do {
                let jsonResult: NSDictionary = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
                if let people : [NSDictionary] = jsonResult["person"] as? [NSDictionary] {
                    for person: NSDictionary in people {
                        for (name,value) in person {
                            print("\(name) , \(value)")
                        }
                    }
                }
            } catch {}
        } catch {}
    }
14

Обновлены имена Swift 3.0

На основе Ответ Abhishek и ответ Друвы

func loadJson(forFilename fileName: String) -> NSDictionary? {

    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? NSDictionary

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

    return nil
}
10

Swift 3.0, Xcode 8, iOS 10

 if let path = Bundle.main.url(forResource: "person", withExtension: "json") {

        do {
            let jsonData = try Data(contentsOf: path, options: .mappedIfSafe)
            do {
                if let jsonResult = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions(rawValue: 0)) as? NSDictionary {
                    if let personArray = jsonResult.value(forKey: "person") as? NSArray {
                        for (_, element) in personArray.enumerated() {
                            if let element = element as? NSDictionary {
                                let name = element.value(forKey: "name") as! String
                                let age = element.value(forKey: "age") as! String
                                let employed = element.value(forKey: "employed") as! String
                                print("Name: \(name),  age: \(age), employed: \(employed)")
                            }
                        }
                    }
                }
            } catch let error as NSError {
                print("Error: \(error)")
            }
        } catch let error as NSError {
            print("Error: \(error)")
        }
    }

Вывод:

Name: Bob,  age: 16, employed: No
Name: Vinny,  age: 56, employed: Yes
10

Ответ Swift 2.1 (на основе Abhishek's):

    if let path = NSBundle.mainBundle().pathForResource("test", ofType: "json") {
        do {
            let jsonData = try NSData(contentsOfFile: path, options: NSDataReadingOptions.DataReadingMappedIfSafe)
            do {
                let jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
                if let people : [NSDictionary] = jsonResult["person"] as? [NSDictionary] {
                    for person: NSDictionary in people {
                        for (name,value) in person {
                            print("\(name) , \(value)")
                        }
                    }
                }
            } catch {}
        } catch {}
    }
7
fileprivate class BundleTargetingClass {}
func loadJSON<T>(name: String) -> T? {
  guard let filePath = Bundle(for: BundleTargetingClass.self).url(forResource: name, withExtension: "json") else {
    return nil
  }

  guard let jsonData = try? Data(contentsOf: filePath, options: .mappedIfSafe) else {
    return nil
  }

  guard let json = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) else {
    return nil
  }

  return json as? T
}

готово к копированию, стороннее независимое от платформы решение.

использование

let json:[[String : AnyObject]] = loadJSON(name: "Stations")!

  • 0
    это сработало для меня. Мне нужно было жестко закодировать список доступных для поиска лекарств в приложение. Я получил файл JSON из базы данных MySQL. Я поместил файл json в мой проект XCODE, запущенный выше в viewDidLoad, и я получил свой словарь json !!!
7

Это отлично поработало со мной

func readjson(fileName: String) -> NSData{

    let path = NSBundle.mainBundle().pathForResource(fileName, ofType: "json")
    let jsonData = NSData(contentsOfMappedFile: path!)

    return jsonData!
}
6

Вот мое решение, используя SwiftyJSON

if let path : String = NSBundle.mainBundle().pathForResource("filename", ofType: "json") {
    if let data = NSData(contentsOfFile: path) {

        let json = JSON(data: data)

    }
}
5

Я даю другой ответ, потому что ни один из них не предназначен для загрузки ресурса из тестового пакета. Если вы используете удаленный сервис, который использует JSON и хотите выполнить модульное тестирование, анализируя результаты, не затрагивая реальный сервис, вы берете один или несколько ответов и помещаете их в файлы в папке "Тесты" в своем проекте.

func testCanReadTestJSONFile() {
    let path = NSBundle(forClass: ForecastIOAdapterTests.self).pathForResource("ForecastIOSample", ofType: "json")
    if let jsonData = NSData(contentsOfFile:path!) {
        let json = JSON(data: jsonData)
        if let currentTemperature = json["currently"]["temperature"].double {
            println("json: \(json)")
            XCTAssertGreaterThan(currentTemperature, 0)
        }
    }
}

Здесь также используется SwiftyJSON, но основная логика получения тестового пакета и загрузки файла - ответ на вопрос.

3

Последний быстрый 3.0 полностью работает

func loadJson(filename fileName: String) -> [String: AnyObject]?
{
    if let url = Bundle.main.url(forResource: fileName, withExtension: "json") 
{
      if let data = NSData(contentsOf: url) {
          do {
                    let object = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        return dictionary
                    }
                } catch {
                    print("Error!! Unable to parse  \(fileName).json")
                }
            }
            print("Error!! Unable to load  \(fileName).json")
        }
        return nil
    }
2

Обновлен для Swift 3 безопасным способом

    private func readLocalJsonFile() {

    if let urlPath = Bundle.main.url(forResource: "test", withExtension: "json") {

        do {
            let jsonData = try Data(contentsOf: urlPath, options: .mappedIfSafe)

            if let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String: AnyObject] {

                if let personArray = jsonDict["person"] as? [[String: AnyObject]] {

                    for personDict in personArray {

                        for (key, value) in personDict {

                            print(key, value)
                        }
                        print("\n")
                    }
                }
            }
        }

        catch let jsonError {
            print(jsonError)
        }
    }
}

Изображение 1863

1

Swift 4: опробуйте мое решение:

test.json

{
    "person":[
        {
            "name": "Bob",
            "age": "16",
            "employed": "No"
        },
        {
            "name": "Vinny",
            "age": "56",
            "employed": "Yes"
        }
    ]
}

RequestCodable.swift

import Foundation

struct RequestCodable:Codable {
    let person:[PersonCodable]
}

PersonCodable.swift

import Foundation

struct PersonCodable:Codable {
    let name:String
    let age:String
    let employed:String
}

Декодируемый + FromJSON.swift

import Foundation

extension Decodable {

    static func fromJSON<T:Decodable>(_ fileName: String, fileExtension: String="json", bundle: Bundle = .main) throws -> T {
        guard let url = bundle.url(forResource: fileName, withExtension: fileExtension) else {
            throw NSError(domain: NSURLErrorDomain, code: NSURLErrorResourceUnavailable)
        }

        let data = try Data(contentsOf: url)

        return try JSONDecoder().decode(T.self, from: data)
    }
}

Пример:

let result = RequestCodable.fromJSON("test") as RequestCodable?

result?.person.compactMap({ print($0) }) 

/*
PersonCodable(name: "Bob", age: "16", employed: "No")
PersonCodable(name: "Vinny", age: "56", employed: "Yes")
*/
  • 0
    Ваша fromJSON расширения fromJSON выбрасывает, но в примере вы вызываете ее без ключевого слова try . Этот код не будет компилироваться.
  • 0
    Кроме того, для fromJSON вы используете расширение Decodable, но при этом вы не используете информацию из типа Decodable, но предоставляете дополнительные (совершенно бесполезные) обобщения.
1

Swift 4.1 обновил Xcode 9.2

if let filePath = Bundle.main.path(forResource: "fileName", ofType: "json"), let data = NSData(contentsOfFile: filePath) {

     do {
      let json = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions.allowFragments)        
        }
     catch {
                //Handle error
           }
 }
  • 3
    В этом нет ничего нового, скорее наоборот: не используйте NSData в Swift 3+, и .allowFragments в этом случае не имеет смысла.
1

Это работало для меня с XCode 8.3.3

func fetchPersons(){

    if let pathURL = Bundle.main.url(forResource: "Person", withExtension: "json"){

        do {

            let jsonData = try Data(contentsOf: pathURL, options: .mappedIfSafe)

            let jsonResult = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String: Any]
            if let persons = jsonResult["person"] as? [Any]{

                print(persons)
            }

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

Основываясь на Ответ Abhishek, для iOS 8 это будет:

let masterDataUrl: NSURL = NSBundle.mainBundle().URLForResource("masterdata", withExtension: "json")!
let jsonData: NSData = NSData(contentsOfURL: masterDataUrl)!
let jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: nil) as! NSDictionary
var persons : NSArray = jsonResult["person"] as! NSArray
  • 0
    ОШИБКА: дополнительная error agrument в вызове.
  • 0
    Вы используете Swift 2.0? Тогда да, это было бы так. На это ответили до-2.0.
Показать ещё 1 комментарий
0

Сначала создайте кодируемый Struc следующим образом:

  struct JuzgadosList : Codable {
    var CP : Int
    var TEL : String
    var LOCAL : String
    var ORGANO : String
    var DIR : String
}

Теперь объявите переменную

 var jzdosList = [JuzgadosList]()

Читать из основного каталога

func getJsonFromDirectory() {

        if let path = Bundle.main.path(forResource: "juzgados", ofType: "json") {
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
                let jList = try JSONDecoder().decode([JuzgadosList].self, from: data)
                self.jzdosList = jList

                DispatchQueue.main.async() { () -> Void in
                    self.tableView.reloadData()
                }

            } catch let error {
                print("parse error: \(error.localizedDescription)")
            }
        } else {
            print("Invalid filename/path.")
        }
    }

Читать из Интернета

func getJsonFromUrl(){

        self.jzdosList.removeAll(keepingCapacity: false)

        print("Internet Connection Available!")

        guard let url = URL(string: "yourURL")  else { return }

        let request = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
        URLSession.shared.dataTask(with: request) { (data, response, err) in
            guard let data = data else { return }
            do {
                let jList = try JSONDecoder().decode([JuzgadosList].self, from: data)
                self.jzdosList = jList

                DispatchQueue.main.async() { () -> Void in
                    self.tableView.reloadData()
                }
            } catch let jsonErr {
                print("Error serializing json:", jsonErr)
            }
        }.resume()
    }
0

SWIFTYJSON VERSION SWIFT 3

func loadJson(fileName: String) -> JSON {

    var dataPath:JSON!

    if let path : String = Bundle.main.path(forResource: fileName, ofType: "json") {
        if let data = NSData(contentsOfFile: path) {
             dataPath = JSON(data: data as Data)
        }
    }
    return dataPath
}
0

Я также могу рекомендовать Ray Wenderlich Swift JSON Tutorial (в котором также рассматривается удивительная альтернатива SwiftyJSON, Gloss). Выдержка (которая сама по себе не дает полного ответа на плакат, но добавленная стоимость этого ответа - это ссылка, поэтому нет -1 для этого, пожалуйста):

В Objective-C разбор и десериализация JSON довольно проста:

NSArray *json = [NSJSONSerialization JSONObjectWithData:JSONData
options:kNilOptions error:nil];
NSString *age = json[0][@"person"][@"age"];
NSLog(@"Dani age is %@", age);

В Swift разбор и десериализация JSON немного утомительны из-за возможностей Swift и типа безопасности [но как] Swift 2.0 был введен оператор guard, чтобы помочь избавиться от вложенных операторов if:

var json: Array!
do {
  json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions()) as? Array
} catch {
  print(error)
}

guard let item = json[0] as? [String: AnyObject],
  let person = item["person"] as? [String: AnyObject],
  let age = person["age"] as? Int else {
    return;
}
print("Dani age is \(age)")

Конечно, в XCode 8.x вы просто дважды коснитесь пробела и скажите "Эй, Сири, пожалуйста, десериализуйте этот JSON для меня в Swift 3.0 с пробелами/вкладками".

0

Я использовал код ниже для получения JSON из файла FAQ-data.json, присутствующего в каталоге проекта.

Im реализует в Xcode 7.3 с помощью Swift.

     func fetchJSONContent() {
            if let path = NSBundle.mainBundle().pathForResource("FAQ-data", ofType: "json") {

                if let jsonData = NSData(contentsOfFile: path) {
                    do {
                        if let jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {

                            if let responseParameter : NSDictionary = jsonResult["responseParameter"] as? NSDictionary {

                                if let response : NSArray = responseParameter["FAQ"] as? NSArray {
                                    responseFAQ = response
                                    print("response FAQ : \(response)")
                                }
                            }
                        }
                    }
                    catch { print("Error while parsing: \(error)") }
                }
            }
        }

override func viewWillAppear(animated: Bool) {
        fetchFAQContent()
    }

Структура файла JSON:

{
    "status": "00",
    "msg": "FAQ List ",
    "responseParameter": {
        "FAQ": [
            {                
                "question": "Question No.1 here",
                "answer": "Answer goes here",  
                "id": 1
            },
            {                
                "question": "Question No.2 here",
                "answer": "Answer goes here",
                "id": 2
            }
            . . .
        ]
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню