Swift 3에서 JSON을 올바르게 구문 분석


123

JSON 응답을 가져오고 결과를 변수에 저장하려고합니다. 저는이 코드의 버전이 Xcode 8의 GM 버전이 출시 될 때까지 Swift의 이전 릴리스에서 작동했습니다. I에 유래에 대한 몇 가지 유사한 게시물을 살펴했다 : 스위프트 2 구문 분석 JSON을 - 형 'AnyObject'의 값 첨자 할 수 없습니다스위프트 3에서 JSON 구문 분석을 .

그러나 그곳에서 전달 된 아이디어는이 시나리오에 적용되지 않는 것 같습니다.

Swift 3에서 JSON 응답을 올바르게 구문 분석하려면 어떻게해야합니까? Swift 3에서 JSON을 읽는 방식이 변경 되었습니까?

다음은 문제의 코드입니다 (플레이 그라운드에서 실행할 수 있음).

import Cocoa

let url = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"

if let url = NSURL(string: url) {
    if let data = try? Data(contentsOf: url as URL) {
        do {
            let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)

        //Store response in NSDictionary for easy access
        let dict = parsedData as? NSDictionary

        let currentConditions = "\(dict!["currently"]!)"

        //This produces an error, Type 'Any' has no subscript members
        let currentTemperatureF = ("\(dict!["currently"]!["temperature"]!!)" as NSString).doubleValue

            //Display all current conditions from API
            print(currentConditions)

            //Output the current temperature in Fahrenheit
            print(currentTemperatureF)

        }
        //else throw an error detailing what went wrong
        catch let error as NSError {
            print("Details of JSON parsing error:\n \(error)")
        }
    }
}

편집 : 다음은 API 호출 결과의 샘플입니다.print(currentConditions)

["icon": partly-cloudy-night, "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precipIntensity": 0, "windSpeed": 6.04, "summary": Partly Cloudy, "ozone": 321.13, "temperature": 49.45, "dewPoint": 41.75, "apparentTemperature": 47, "windBearing": 332, "cloudCover": 0.28, "time": 1480846460]

API 호출에서 반환 된 샘플 데이터를 넣을 수 있습니까?
User

1
예, 방금 print (currentConditions) 후에 인쇄 된 결과 샘플을 추가했습니다. 도움이 되었기를 바랍니다.
user2563039 2016-12-04

Codable 프로토콜을 사용하여 swift4에서 json 구문 분석 stackoverflow.com/a/52931265/9316566
Naser Mohamed

답변:


172

우선 원격 URL에서 동 기적으로 데이터를로드하지 , 항상 같은 비동기 방법을 사용합니다 URLSession.

'Any'에는 아래 첨자 멤버가 없습니다.

컴파일러가 중간 오브젝트 (예를 들어 있습니다 입력 한 내용의 아무 생각이 없기 때문에 발생 currently에서 ["currently"]!["temperature"])와 같은 당신이 재단 수집 유형을 사용하기 때문에 NSDictionary컴파일러가 타입에 대해 전혀 모르고있다가.

또한 Swift 3에서는 모든 첨자 된 객체 의 유형에 대해 컴파일러에 알려야 합니다.

JSON 직렬화의 결과를 실제 유형으로 캐스팅해야합니다.

이 코드 사용 URLSession전용 스위프트 기본 유형

let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"

let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
  if error != nil {
    print(error)
  } else {
    do {

      let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
      let currentConditions = parsedData["currently"] as! [String:Any]

      print(currentConditions)

      let currentTemperatureF = currentConditions["temperature"] as! Double
      print(currentTemperatureF)
    } catch let error as NSError {
      print(error)
    }
  }

}.resume()

모든 키 / 값 쌍을 인쇄하려면 currentConditions쓸 수 있습니다.

 let currentConditions = parsedData["currently"] as! [String:Any]

  for (key, value) in currentConditions {
    print("\(key) - \(value) ")
  }

관련 참고 사항 jsonObject(with data:

많은 (모두 보이는) 튜토리얼 이 Swift에서 완전히 말도 안되는 옵션 .mutableContainers이나 제안을 제안 .mutableLeaves합니다. 두 가지 옵션은 결과를 NSMutable...개체 에 할당하는 레거시 Objective-C 옵션 입니다. Swift에서 모든 variable은 기본적으로 변경 가능하며 이러한 옵션 중 하나를 전달하고 결과를 let상수에 할당 해도 전혀 효과가 없습니다. 더 나아가 대부분의 구현은 어쨌든 역 직렬화 된 JSON을 변경하지 않습니다.

Swift에서 유용한 유일한 (희귀 한) 옵션 .allowFragments은 JSON 루트 객체가 컬렉션 유형 ( 또는 ) 중 하나가 아닌 값 유형 ( , 또는 ) String일 수있는 경우에 필요한 옵션입니다 . 그러나 일반적으로 옵션 없음 을 의미 하는 매개 변수를 생략합니다 .NumberBoolnullarraydictionaryoptions

================================================ =========================

JSON 구문 분석에 대한 몇 가지 일반적인 고려 사항

JSON은 잘 정렬 된 텍스트 형식입니다. JSON 문자열을 읽는 것은 매우 쉽습니다. 문자열을주의 깊게 읽으십시오 . 컬렉션 유형 2 개와 값 유형 4 개 등 6 가지 유형 만 있습니다.


컬렉션 유형은 다음과 같습니다.

  • 배열 -JSON : 대괄호 안의 객체 []-Swift : [Any]그러나 대부분의 경우[[String:Any]]
  • 사전 -JSON : 중괄호 안의 객체 {}-Swift :[String:Any]

값 유형은 다음과 같습니다.

  • 문자열 -JSON : 큰 따옴표로 묶인 모든 값 "Foo", 짝수 "123"또는 "false"– Swift :String
  • 숫자 -JSON : 큰 따옴표가 없는 숫자 값 123또는 123.0– Swift : Int또는Double
  • Bool -JSON : true또는 큰 따옴표로 묶지 false 않음 – Swift : true또는false
  • null -JSON : null– Swift :NSNull

JSON 사양에 따라 사전의 모든 키는 String.


기본적으로 선택적 바인딩을 사용하여 옵션을 안전하게 풀기 위해 항상 권장됩니다.

루트 객체가 사전 ( {})이면 유형을[String:Any]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...

( OneOfSupportedJSONTypes는 위에 설명 된대로 JSON 컬렉션 또는 값 유형입니다.)

if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
    print(foo)
} 

루트 객체가 배열 ( [])이면 유형을[[String:Any]]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...

다음을 사용하여 배열을 반복합니다.

for item in parsedData {
    print(item)
}

특정 인덱스에 항목이 필요한 경우 인덱스가 있는지도 확인하십시오.

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
   let item = parsedData[2] as? OneOfSupportedJSONTypes {
      print(item)
    }
}

드물지만 JSON이 컬렉션 유형이 아니라 값 유형 중 하나 인 경우 .allowFragments옵션 을 전달 하고 결과를 적절한 값 유형으로 캐스팅해야합니다.

if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...

Apple은 Swift Blog : Working with JSON in Swift에 포괄적 인 기사를 게시했습니다.


================================================ =========================

Swift 4+에서 Codable프로토콜은 JSON을 구조체 / 클래스로 직접 구문 분석하는보다 편리한 방법을 제공합니다.

예를 들어 질문에 제공된 JSON 샘플 (약간 수정 됨)

let jsonString = """
{"icon": "partly-cloudy-night", "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precip_intensity": 0, "wind_speed": 6.04, "summary": "Partly Cloudy", "ozone": 321.13, "temperature": 49.45, "dew_point": 41.75, "apparent_temperature": 47, "wind_bearing": 332, "cloud_cover": 0.28, "time": 1480846460}
"""

struct로 디코딩 할 수 있습니다 Weather. Swift 유형은 위에서 설명한 것과 동일합니다. 몇 가지 추가 옵션이 있습니다.

  • 를 나타내는 문자열 URL로 직접 디코딩 할 수있다 URL.
  • time정수로 디코딩 될 수 DatedateDecodingStrategy .secondsSince1970.
  • snaked_cased JSON 키는 다음을 사용하여 camelCase 로 변환 할 수 있습니다 .keyDecodingStrategy .convertFromSnakeCase

struct Weather: Decodable {
    let icon, summary: String
    let pressure: Double, humidity, windSpeed : Double
    let ozone, temperature, dewPoint, cloudCover: Double
    let precipProbability, precipIntensity, apparentTemperature, windBearing : Int
    let time: Date
}

let data = Data(jsonString.utf8)
do {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Weather.self, from: data)
    print(result)
} catch {
    print(error)
}

기타 코딩 가능한 소스 :


이것은 매우 도움이됩니다. 위의 코드가 놀이터에서 실행될 때 보이는 출력이 표시되지 않는 이유가 궁금합니다.
user2563039

위에서 언급했듯이 dict!["currently"]!컴파일러가 후속 키 구독을 안전하게 추론 할 수 있는 모호한 결과를 사전 에 캐스팅해야합니다 .
vadian

1
Apple 기사는 꽤 멋지지만 어떤 이유로 든 swift 3으로 실행할 수 없습니다. 유형 [String : Any]에 대해 불평합니까? 아래 첨자 멤버가 없습니다. 다른 문제도 있었지만 해결할 수있었습니다. 누구나 실제로 실행되는 코드의 예가 있습니까?
Shades

@Shades 질문을하고 코드를 게시하세요. 대부분의 문제는 래핑되지 않은 옵션과 관련이 있습니다.
vadian nov.

API 호출에서 반환 된 샘플 데이터를 넣을 수 있습니까?
User

12

스위프트 3 엑스 코드 8 베타 6에 일어난 큰 변화는 해당 ID가 지금 수입이었다 Any보다는 AnyObject.

이것은 parsedData유형과 가장 가능성이 높은 사전으로 반환 된다는 것을 의미합니다 [Any:Any]. 디버거를 사용하지 않고는 캐스트 NSDictionary가 수행 할 작업 을 정확히 말할 수 없지만 표시되는 오류 dict!["currently"]!는 유형 이 있기 때문입니다.Any

그래서 어떻게 해결합니까? 당신이 그것을 참조한 방식에서 나는 dict!["currently"]!사전 이라고 가정 하고 그래서 당신은 많은 옵션이 있습니다.

먼저 다음과 같이 할 수 있습니다.

let currentConditionsDictionary: [String: AnyObject] = dict!["currently"]! as! [String: AnyObject]  

그러면 값을 쿼리 할 수있는 사전 개체가 제공되므로 다음과 같이 온도를 얻을 수 있습니다.

let currentTemperatureF = currentConditionsDictionary["temperature"] as! Double

또는 원하는 경우 줄을 서서 할 수 있습니다.

let currentTemperatureF = (dict!["currently"]! as! [String: AnyObject])["temperature"]! as! Double

이것이 도움이되기를 바라며, 테스트 할 샘플 앱을 작성할 시간이 없었습니다.

마지막 메모 : 가장 쉬운 방법 [String: AnyObject]은 처음에 JSON 페이로드를 바로 캐스팅하는 것 입니다.

let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments) as! Dictionary<String, AnyObject>

dict!["currently"]! as! [String: String]충돌합니다
vadian

추락 한 지점은 [ "온도"] !! 또한 문자열을 NSString으로 캐스트하려고 시도합니다. 새 솔루션이 swiftlang.ng.bluemix.net/#/repl/57d3bc683a422409bf36c391
discorevilo

[String: String]두 개의 숫자 값이 있기 때문에 전혀 작동하지 않습니다. 그것은 작동하지 않습니다 놀이터
vadian

@vadian 아, 예, 나는 그것들과 신속한 샌드 박스가 유용하게 숨겨져 있다는 것을 알지 못했습니다! -이제 [다시 한 번] 수정되었습니다 (macOS에서 테스트 됨). 이 밖에 :) 가리키는 주셔서 감사합니다
discorevilo

6
let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"

let data = str.data(using: String.Encoding.utf8, allowLossyConversion: false)!

do {
    let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
    if let names = json["names"] as? [String] 
{
        print(names)
}
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")
}

5

저는 이 목적을 위해 정확히 퀵 타입을 만들었 습니다 . 샘플 JSON을 붙여 넣기 만하면 quicktype이 API 데이터에 대해 다음 유형 계층을 생성합니다.

struct Forecast {
    let hourly: Hourly
    let daily: Daily
    let currently: Currently
    let flags: Flags
    let longitude: Double
    let latitude: Double
    let offset: Int
    let timezone: String
}

struct Hourly {
    let icon: String
    let data: [Currently]
    let summary: String
}

struct Daily {
    let icon: String
    let data: [Datum]
    let summary: String
}

struct Datum {
    let precipIntensityMax: Double
    let apparentTemperatureMinTime: Int
    let apparentTemperatureLowTime: Int
    let apparentTemperatureHighTime: Int
    let apparentTemperatureHigh: Double
    let apparentTemperatureLow: Double
    let apparentTemperatureMaxTime: Int
    let apparentTemperatureMax: Double
    let apparentTemperatureMin: Double
    let icon: String
    let dewPoint: Double
    let cloudCover: Double
    let humidity: Double
    let ozone: Double
    let moonPhase: Double
    let precipIntensity: Double
    let temperatureHigh: Double
    let pressure: Double
    let precipProbability: Double
    let precipIntensityMaxTime: Int
    let precipType: String?
    let sunriseTime: Int
    let summary: String
    let sunsetTime: Int
    let temperatureMax: Double
    let time: Int
    let temperatureLow: Double
    let temperatureHighTime: Int
    let temperatureLowTime: Int
    let temperatureMin: Double
    let temperatureMaxTime: Int
    let temperatureMinTime: Int
    let uvIndexTime: Int
    let windGust: Double
    let uvIndex: Int
    let windBearing: Int
    let windGustTime: Int
    let windSpeed: Double
}

struct Currently {
    let precipProbability: Double
    let humidity: Double
    let cloudCover: Double
    let apparentTemperature: Double
    let dewPoint: Double
    let ozone: Double
    let icon: String
    let precipIntensity: Double
    let temperature: Double
    let pressure: Double
    let precipType: String?
    let summary: String
    let uvIndex: Int
    let windGust: Double
    let time: Int
    let windBearing: Int
    let windSpeed: Double
}

struct Flags {
    let sources: [String]
    let isdStations: [String]
    let units: String
}

또한 강력한 형식의 값을 빠르게 구문 분석하고 해당 필드에 액세스 할 수 있도록 JSON 문자열을 사용하는 편의 생성자를 포함하여 의 반환 값을 JSONSerialization.jsonObject으로 동축하는 종속성없는 마샬링 코드를 생성 합니다.ForecastForecast

let forecast = Forecast.from(json: jsonString)!
print(forecast.daily.data[0].windGustTime)

npm에서 quicktype을 설치 npm i -g quicktype하거나 웹 UI사용하여 생성 된 전체 코드를 플레이 그라운드에 붙여 넣을 수 있습니다.


링크가 실패합니다.
drew ..

환상적인 시간 절약! 잘 했어!
marko apr

1
훌륭한 도구. 감사.
Ahmet Ardal 2018

4

업데이트isConnectToNetwork-Function 이것 이후, 덕분에 게시물을 .

나는 그것에 대한 추가 방법을 썼다.

import SystemConfiguration

func loadingJSON(_ link:String, postString:String, completionHandler: @escaping (_ JSONObject: AnyObject) -> ()) {

    if(isConnectedToNetwork() == false){
        completionHandler("-1" as AnyObject)
        return
    }

    let request = NSMutableURLRequest(url: URL(string: link)!)
    request.httpMethod = "POST"
    request.httpBody = postString.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
        guard error == nil && data != nil else { // check for fundamental networking error
            print("error=\(error)")
            return
        }

        if let httpStatus = response as? HTTPURLResponse , httpStatus.statusCode != 200 { // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }
        //JSON successfull
        do {
            let parseJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
            DispatchQueue.main.async(execute: {
                completionHandler(parseJSON as AnyObject)
            });
        } catch let error as NSError {
            print("Failed to load: \(error.localizedDescription)")
        }
    }
    task.resume()
}

func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
            SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
        }
    }

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
        return false
    }

    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    let ret = (isReachable && !needsConnection)

    return ret
}

이제 앱에서 원하는 곳 어디에서나 쉽게 호출 할 수 있습니다.

loadingJSON("yourDomain.com/login.php", postString:"email=\(userEmail!)&password=\(password!)") { parseJSON in

    if(String(describing: parseJSON) == "-1"){
        print("No Internet")
    } else {

    if let loginSuccessfull = parseJSON["loginSuccessfull"] as? Bool {
        //... do stuff
    }
}

Marco, 프로젝트에이 기능을 추가하는 가장 좋은 방법은 무엇입니까? 어떤 contorller 또는 모델에서?
KamalPanhwar

헤이, 당신은 여분의 신속한 파일이나 클래스에 첫 번째 메소드 func loadingJSON (...)을 추가하기 만하면됩니다. 그 후 프로젝트의 모든 컨트롤러에서 이것을 호출 할 수 있습니다
Marco Weber

나는 그것을 시도했지만 완전한 솔루션을 시연하는 아이디어와 도우미 메서드 isConnectedToNetwork ()를 포함하여 그것을 사용하는 방법을 좋아합니다. 아마 좋은 코드로 구현하는 방법에 대한 아이디어
Amr Angry

그래서 방금 새 swift-file (프로젝트 트리에서 왼쪽 클릭, 새 파일 ..., swift 파일)을 사용하고 jsonhelper.swift라고 불렀습니다. 이 파일에 첫 번째 코드 인 loadingJSON () 및 isConnectedToNetwork ()를 배치합니다. 그 후에는 프로젝트의 모든 부분에서이 두 가지 기능을 사용할 수 있습니다. 예를 들어 loginVC에서 로그인 버튼의 동작으로 두 번째 코드를 사용할 수 있습니다. 분명히 도메인, 게시 문자열 및 paseJson 값 (parseJSON [ "loginSuccessfull"])을 변경해야합니다. 당신의 PHP 파일
마르코 베버

0

Swift에는 강력한 유형 추론이 있습니다. "if let"또는 "guard let"상용구를 제거하고 기능적 접근 방식을 사용하여 강제로 언 래핑합니다.

  1. 여기 JSON이 있습니다. 선택적 JSON 또는 평소를 사용할 수 있습니다. 이 예제에서는 선택 사항을 사용하고 있습니다.

    let json: Dictionary<String, Any>? = ["current": ["temperature": 10]]
  1. 도우미 기능. 한 번만 작성하고 사전에 재사용하면됩니다.

    /// Curry
    public func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
        return { a in
            { f(a, $0) }
        }
    }

    /// Function that takes key and optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key, _ json: Dictionary<Key, Any>?) -> Value? {
        return json.flatMap {
            cast($0[key])
        }
    }

    /// Function that takes key and return function that takes optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key) -> (Dictionary<Key, Any>?) -> Value? {
        return curry(extract)(key)
    }

    /// Precedence group for our operator
    precedencegroup RightApplyPrecedence {
        associativity: right
        higherThan: AssignmentPrecedence
        lowerThan: TernaryPrecedence
    }

    /// Apply. g § f § a === g(f(a))
    infix operator § : RightApplyPrecedence
    public func §<A, B>(_ f: (A) -> B, _ a: A) -> B {
        return f(a)
    }

    /// Wrapper around operator "as".
    public func cast<A, B>(_ a: A) -> B? {
        return a as? B
    }
  1. 그리고 여기에 우리의 마법이 있습니다-가치 추출 :

    let temperature = (extract("temperature") § extract("current") § json) ?? NSNotFound

한 줄의 코드로 강제 풀림이나 수동 유형 캐스팅이 없습니다. 이 코드는 플레이 그라운드에서 작동하므로 복사하여 확인할 수 있습니다. 다음은 GitHub 의 구현 입니다.


0

이것은 문제를 해결하는 다른 방법입니다. 따라서 아래 솔루션을 확인하십시오. 도움이되기를 바랍니다.

let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"
let data = str.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
    let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
    if let names = json["names"] as? [String] {
        print(names)
    }
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")
}

0

문제는 API 상호 작용 방법에 있습니다. JSON 구문 분석은 구문에서만 변경됩니다. 주요 문제는 데이터를 가져 오는 방법입니다. 사용중인 것은 데이터를 가져 오는 동기식 방법입니다. 이것은 모든 경우에 작동하지 않습니다. 사용해야하는 것은 데이터를 가져 오는 비동기식 방법입니다. 이런 식으로 API를 통해 데이터를 요청하고 데이터로 응답 할 때까지 기다려야합니다. URL 세션 및 Alamofire. 다음은 URL 세션 방법에 대한 코드입니다.

let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"
let url = URL.init(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
    guard error == nil else {
        print(error)
    }
    do {
        let Data = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
        // Note if your data is coming in Array you should be using [Any]()
        //Now your data is parsed in Data variable and you can use it normally
        let currentConditions = Data["currently"] as! [String:Any]
        print(currentConditions)
        let currentTemperatureF = currentConditions["temperature"] as! Double
        print(currentTemperatureF)
    } catch let error as NSError {
        print(error)
    }
}.resume()

0
{
    "User":[
      {
        "FirstUser":{
        "name":"John"
        },
       "Information":"XY",
        "SecondUser":{
        "name":"Tom"
      }
     }
   ]
}

이전 json을 사용하여 모델 을 생성하는 경우이 링크를 사용하여 [블로그] : http://www.jsoncafe.com 을 사용하여 Codable 구조 또는 모든 형식 생성

모델

import Foundation
struct RootClass : Codable {
    let user : [Users]?
    enum CodingKeys: String, CodingKey {
        case user = "User"
    }

    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        user = try? values?.decodeIfPresent([Users].self, forKey: .user)
    }
}

struct Users : Codable {
    let firstUser : FirstUser?
    let information : String?
    let secondUser : SecondUser?
    enum CodingKeys: String, CodingKey {
        case firstUser = "FirstUser"
        case information = "Information"
        case secondUser = "SecondUser"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        firstUser = try? FirstUser(from: decoder)
        information = try? values?.decodeIfPresent(String.self, forKey: .information)
        secondUser = try? SecondUser(from: decoder)
    }
}
struct SecondUser : Codable {
    let name : String?
    enum CodingKeys: String, CodingKey {
        case name = "name"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        name = try? values?.decodeIfPresent(String.self, forKey: .name)
    }
}
struct FirstUser : Codable {
    let name : String?
    enum CodingKeys: String, CodingKey {
        case name = "name"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        name = try? values?.decodeIfPresent(String.self, forKey: .name)
    }
}

구문 분석

    do {
        let res = try JSONDecoder().decode(RootClass.self, from: data)
        print(res?.user?.first?.firstUser?.name ?? "Yours optional value")
    } catch {
        print(error)
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.