我真的在努力把一个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。


当前回答

Swift 2.1答案(基于Abhishek):

    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 {}
    }

其他回答

我可能还会推荐Ray Wenderlich的Swift JSON教程(它还涵盖了很棒的SwiftyJSON替代品,Gloss)。一段摘录(它本身并不能完全回答海报上的问题,但这个答案的附加价值是链接,所以请不要给它加-1):

在Objective-C中,解析和反序列化JSON相当简单:

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

在Swift中,由于Swift的可选选项和类型安全,解析和反序列化JSON有点繁琐,但作为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's age is \(age)")

当然,在XCode 8中。x,你只需双击空格键,然后说“嘿,Siri,请在Swift 3.0中用空格/制表符缩进为我反序列化这个JSON。”

如果有人正在寻找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.")
}

Swift 5.1, Xcode 11

你可以用这个:


struct Person : Codable {
    let name: String
    let lastName: String
    let age: Int
}

func loadJson(fileName: String) -> Person? {
   let decoder = JSONDecoder()
   guard
        let url = Bundle.main.url(forResource: fileName, withExtension: "json"),
        let data = try? Data(contentsOf: url),
        let person = try? decoder.decode(Person.self, from: data)
   else {
        return nil
   }

   return person
}

我浪费了我的时间在定位文件,它位于我的项目与名称Jsondata.json。但是我无法通过代码....找到我的文件

解决方案:确保您的Jsondata。在项目>构建阶段>复制Bundle资源中添加了json文件。否则你将无法获得file和Bundle.main。url(forResource: fileName, witheextension: "json")将总是给你nil。

这里还有一个答案??

好的。坚持住!之前所有的答案都是关于使用JSONSerialization,或返回nil,或忽略错误。

有什么不同

“我的解决方案”(不是真的我的解决方案,这是上述解决方案的混合)包含:

返回值的现代方法:Result<Value,Error>(返回值或错误) 避免使用空值 包含一个稍微详细的错误 使用扩展有漂亮/直观的界面: 提供了选择包的可能性

细节

Xcode 14 斯威夫特5.6.1

解决方案1。JSON文件->可解码

enum JSONParseError: Error {
    case fileNotFound
    case dataInitialisation(error: Error)
    case decoding(error: Error)
}

extension Decodable {
    static func from(localJSON filename: String,
                     bundle: Bundle = .main) -> Result<Self, JSONParseError> {
        guard let url = bundle.url(forResource: filename, withExtension: "json") else {
            return .failure(.fileNotFound)
        }
        let data: Data
        do {
            data = try Data(contentsOf: url)
        } catch let error {
            return .failure(.dataInitialisation(error: error))
        }

        do {
            return .success(try JSONDecoder().decode(self, from: data))
        } catch let error {
            return .failure(.decoding(error: error))
        }
    }
}

方案一用途

 struct Model: Decodable {
    let uuid: String
    let name: String
}

switch Model.from(localJSON: "myjsonfile") {
case .success(let value):
    print(value)
case .failure(let error):
    print(error)
}

解决方案2。JSON文件->字典

extension Dictionary where Key == String, Value == Any {

    enum JSONParseError: Error {
        case fileNotFound(filename: String)
        case dataInitialisation(Error)
        case jsonSerialization(Error)
        case mappingFail(value: Any, toType: Any)
    }

    static func from(JSONfile url: URL) -> Result<Self, JSONParseError> {
        let data: Data
        do {
            data = try Data(contentsOf: url)
        } catch let error {
            return .failure(.dataInitialisation(error))
        }

        let jsonObject: Any
        do {
            jsonObject = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
        } catch let error {
            return .failure(.jsonSerialization(error))
        }

        guard let jsonResult = jsonObject as? Self else {
            return .failure(.mappingFail(value: jsonObject, toType: Self.Type.self))
        }

        return .success(jsonResult)
    }

    static func from(localJSONfile name: String) -> Result<Self, JSONParseError> {
        let fileType = "json"
        let fullFileName = name + (name.contains(fileType) ? "" : ".\(fileType)")
        guard let path = Bundle.main.path(forResource: fullFileName, ofType: "") else {
            return .failure(.fileNotFound(filename: fullFileName))
        }
        return from(JSONfile: URL(fileURLWithPath: path))
    }
}

方案二使用

switch [String: Any].from(localJSONfile: "file.json") {
// OR switch [String: Any].from(localJSONfile: "file.json") {
// OR switch [String: Any].from(JSONfile: url) {
case let .success(dictionary):
    print(dictionary)
case let .failure(error):
    print("ERROR: \(error)")
}