Phân tích cú pháp JSON chính xác trong Swift 3


123

Tôi đang cố gắng tìm nạp một phản hồi JSON và lưu trữ các kết quả trong một biến. Tôi đã có các phiên bản mã này hoạt động trong các bản phát hành trước của Swift, cho đến khi phiên bản Xcode 8 của GM được phát hành. Tôi đã xem qua một vài bài viết tương tự trên StackOverflow: Swift 2 Parsing JSON - Không thể đăng ký một giá trị của loại 'AnyObject'JSON Parsing trong Swift 3 .

Tuy nhiên, có vẻ như các ý tưởng được truyền đạt ở đó không áp dụng trong kịch bản này.

Làm cách nào để phân tích chính xác phản hồi JSON trong Swift 3? Có điều gì đó đã thay đổi theo cách đọc JSON trong Swift 3 không?

Dưới đây là mã được đề cập (nó có thể được chạy trong một sân chơi):

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)")
        }
    }
}

Chỉnh sửa: Đây là mẫu kết quả từ lệnh gọi API sauprint(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]

Bạn có thể đặt dữ liệu mẫu được trả về từ lệnh gọi API của mình không?
Người dùng

1
Vâng, tôi vừa thêm một mẫu kết quả được in sau khi in (currentConditions). Hy vọng nó giúp.
dùng2563039

Phân tích cú pháp trong swift4 bằng giao thức Codable stackoverflow.com/a/52931265/9316566
Naser Mohamed

Câu trả lời:


172

Trước hết không bao giờ tải dữ liệu đồng bộ từ một URL từ xa , hãy luôn sử dụng các phương thức không đồng bộ như thế nào URLSession.

'Bất kỳ' không có thành viên đăng ký

xảy ra bởi vì trình biên dịch không có ý tưởng về loại đối tượng trung gian (ví dụ như currentlytrong ["currently"]!["temperature"]) và vì bạn đang sử dụng các loại bộ sưu tập Foundation như NSDictionarytrình biên dịch hoàn toàn không biết gì về loại.

Ngoài ra, trong Swift 3, cần phải thông báo cho trình biên dịch về loại của tất cả các đối tượng được đăng ký.

Bạn phải chuyển kết quả của tuần tự hóa JSON thành loại thực tế.

Mã này sử dụng URLSessionđộc quyền các loại bản địa Swift

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()

Để in tất cả các cặp khóa / giá trị currentConditionsbạn có thể viết

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

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

Một lưu ý liên quan đến jsonObject(with data:

Nhiều hướng dẫn (có vẻ như tất cả) đề xuất .mutableContainershoặc .mutableLeavescác tùy chọn hoàn toàn vô nghĩa trong Swift. Hai tùy chọn là các tùy chọn Objective-C kế thừa để gán kết quả cho NSMutable...các đối tượng. Trong Swift, bất kỳ variable nào cũng có thể thay đổi theo mặc định và chuyển bất kỳ tùy chọn nào trong số đó và gán kết quả cho lethằng số không có tác dụng gì cả. Hơn nữa, hầu hết các triển khai đều không bao giờ làm thay đổi JSON được giải trừ.

Các chỉ (hiếm) tùy chọn đó là hữu ích trong Swift là .allowFragmentsđó là cần thiết nếu nếu đối tượng gốc JSON có thể là một kiểu giá trị ( String, Number, Boolhoặc null) chứ không phải là một trong những loại bộ sưu tập ( arrayhoặc dictionary). Nhưng thông thường bỏ qua optionstham số có nghĩa là Không có tùy chọn .

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

Một số cân nhắc chung để phân tích JSON

JSON là một định dạng văn bản được sắp xếp tốt. Thật dễ dàng để đọc một chuỗi JSON. Đọc chuỗi cẩn thận . Chỉ có sáu loại khác nhau - hai loại bộ sưu tập và bốn loại giá trị.


Các loại bộ sưu tập là

  • Mảng - JSON: các đối tượng trong ngoặc vuông []- Swift: [Any]nhưng trong hầu hết các trường hợp[[String:Any]]
  • Từ điển - JSON: các đối tượng trong dấu ngoặc nhọn {}- Swift:[String:Any]

Các loại giá trị là

  • Chuỗi - JSON: bất kỳ giá trị nào trong dấu ngoặc kép "Foo", chẵn "123"hoặc "false"- Swift:String
  • Số - JSON: giá trị số không nằm trong dấu ngoặc kép 123hoặc 123.0- Swift: InthoặcDouble
  • Bool - JSON: truehoặc false không trong dấu ngoặc kép - Swift: truehoặcfalse
  • null - JSON: null- Swift:NSNull

Theo đặc tả JSON, tất cả các khóa trong từ điển đều phải có String.


Về cơ bản, nó luôn được khuyến nghị sử dụng các ràng buộc tùy chọn cho các tùy chọn mở khóa một cách an toàn

Nếu đối tượng gốc là một từ điển ( {}) truyền kiểu[String:Any]

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

và truy xuất các giá trị bằng các khóa bằng ( OneOfSupportedJSONTypeslà bộ sưu tập JSON hoặc loại giá trị như được mô tả ở trên.)

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

Nếu đối tượng gốc là một mảng ( []) truyền kiểu[[String:Any]]

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

và lặp qua mảng với

for item in parsedData {
    print(item)
}

Nếu bạn cần một mục tại chỉ mục cụ thể, hãy kiểm tra nếu chỉ mục tồn tại

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

Trong trường hợp hiếm hoi, JSON chỉ đơn giản là một trong các loại giá trị - chứ không phải là loại bộ sưu tập - bạn phải chuyển .allowFragmentstùy chọn và chuyển kết quả sang loại giá trị phù hợp chẳng hạn

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

Apple đã xuất bản một bài viết toàn diện trên Blog Swift: Làm việc với JSON trong Swift


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

Trong Swift 4+, Codablegiao thức cung cấp một cách thuận tiện hơn để phân tích JSON trực tiếp thành các cấu trúc / lớp.

Ví dụ: mẫu JSON đã cho trong câu hỏi (được sửa đổi một chút)

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

có thể được giải mã thành struct Weather. Các loại Swift giống như mô tả ở trên. Có một vài lựa chọn bổ sung:

  • Chuỗi đại diện cho một URLcó thể được giải mã trực tiếp như URL.
  • Số timenguyên có thể được giải mã như Datevới dateDecodingStrategy .secondsSince1970.
  • Các khóa JSON của snaken_casing có thể được chuyển đổi thành camelCase vớikeyDecodingStrategy .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)
}

Các nguồn có thể mã hóa khác:


Điều này rất hữu ích. Tôi chỉ tò mò tại sao đoạn mã trên không hiển thị đầu ra có thể nhìn thấy khi nó chạy trong một sân chơi.
dùng2563039

Như đã đề cập ở trên, bạn cần đưa ra kết quả mơ hồ của dict!["currently"]!một từ điển mà trình biên dịch có thể suy ra một cách an toàn đăng ký khóa tiếp theo.
vadian

1
Bài viết của Apple khá thú vị, nhưng tôi không thể bắt nó chạy với swift 3 vì một số lý do. Nó phàn nàn về Loại [Chuỗi: Bất kỳ]? không có thành viên đăng ký. Có một số vấn đề khác với nó, nhưng tôi đã có thể khắc phục nó. Bất cứ ai cũng có một ví dụ về mã của họ thực sự chạy?
Shades

@ Shades Đặt câu hỏi và gửi mã của bạn. Nhiều khả năng vấn đề của bạn có liên quan đến các tùy chọn chưa được mở.
vadian

Bạn có thể đặt dữ liệu mẫu được trả về từ lệnh gọi API của mình không?
Người dùng

12

Một thay đổi lớn đã xảy ra với Xcode 8 Beta 6 cho Swift 3 là id hiện đang nhập Anythay vì AnyObject.

Điều này có nghĩa parsedDatalà được trả về như một từ điển rất có thể với loại [Any:Any]. Không sử dụng trình gỡ lỗi, tôi không thể cho bạn biết chính xác diễn viên của bạn NSDictionarysẽ làm gì nhưng lỗi bạn đang gặp là do dict!["currently"]!có loạiAny

Vì vậy, làm thế nào để bạn giải quyết điều này? Từ cách bạn đã tham chiếu nó, tôi giả sử dict!["currently"]!là một từ điển và vì vậy bạn có nhiều lựa chọn:

Đầu tiên bạn có thể làm một cái gì đó như thế này:

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

Điều này sẽ cung cấp cho bạn một đối tượng từ điển mà sau đó bạn có thể truy vấn các giá trị và do đó bạn có thể nhận được nhiệt độ của mình như thế này:

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

Hoặc nếu bạn muốn bạn có thể làm điều đó theo dòng:

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

Hy vọng rằng điều này có ích, tôi sợ rằng tôi không có thời gian để viết một ứng dụng mẫu để kiểm tra nó.

Một lưu ý cuối cùng: điều dễ nhất để làm, có thể chỉ đơn giản là truyền tải trọng JSON vào [String: AnyObject]ngay khi bắt đầu.

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

dict!["currently"]! as! [String: String]sẽ sụp đổ
vadian

Điểm mà nó bị rơi là ["nhiệt độ"] !! và cũng đang cố gắng truyền String thành NSString - đã xác minh giải pháp mới hoạt động swiftlang.ng.bluemix.net/#/repl/57d3bc683a422409bf36c391
Discorevilo

[String: String]hoàn toàn không thể hoạt động vì có một vài giá trị số. Nó không hoạt động trong Sân chơi Mac
vadian

@vadian ah, vâng, tôi đã không nhận thấy những điều đó và hộp cát nhanh chóng giúp che giấu chúng! - Đã sửa [một lần nữa] ngay bây giờ (và đã thử nghiệm trên macOS). Cảm ơn bạn đã chỉ ra điều này :)
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

Tôi đã xây dựng quicktype chính xác cho mục đích này. Chỉ cần dán JSON mẫu của bạn và quicktype tạo phân cấp loại này cho dữ liệu API của bạn:

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
}

Nó cũng tạo ra mã sắp xếp không phụ thuộc để dỗ giá trị trả về của JSONSerialization.jsonObjecta Forecast, bao gồm cả hàm tạo tiện lợi lấy chuỗi JSON để bạn có thể nhanh chóng phân tích Forecastgiá trị được gõ mạnh và truy cập vào các trường của nó:

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

Bạn có thể cài đặt quicktype từ npm với npm i -g quicktypehoặc sử dụng giao diện người dùng web để lấy mã được tạo hoàn chỉnh để dán vào sân chơi của bạn.


Các liên kết đang thất bại.
đã vẽ ..

Tiết kiệm thời gian tuyệt vời! Làm tốt lắm!
marko

1
Công cụ rực rỡ. Cảm ơn.
Ahmet Ardal

4

Cập nhật các isConnectToNetwork-Functionsau đó, nhờ đó bài .

Tôi đã viết một phương pháp bổ sung cho nó:

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
}

Vì vậy, bây giờ bạn có thể dễ dàng gọi nó trong ứng dụng của bạn bất cứ nơi nào bạn muốn

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, cách tốt nhất để thêm chức năng này trong dự án là gì? trong bất kỳ contorller hoặc mô hình?
KamalPanhwar

này, bạn chỉ cần thêm phương thức đầu tiên func loadJSON (...) trong một tệp hoặc lớp swift bổ sung. Sau đó, bạn có thể gọi nó từ mọi bộ điều khiển trong dự án của bạn
Marco Weber

Tôi đã thử nó, nhưng tôi thích ý tưởng thể hiện một giải pháp đầy đủ và cả cách sử dụng nó bao gồm phương thức của trình trợ giúp isConnectedToNetwork () cho tôi ý tưởng về cách triển khai nó có thể trong mã tốt
Amr Angry

Vì vậy, tôi chỉ sử dụng một tệp swift mới (trái klick trên cây dự án của bạn, tệp mới ..., tệp swift) và gọi nó là jsonhelper.swift. trong tệp này, bạn đặt mã đầu tiên, loadJSON () và isConnectedToNetwork (). sau đó bạn có thể sử dụng hai chức năng này trong mọi phần của dự án. ví dụ: trong loginVC, như một hành động của nút đăng nhập, bạn có thể sử dụng mã thứ hai, rõ ràng bạn phải thay đổi tên miền, chuỗi bài đăng và các giá trị paseJson (parseJSON ["loginSuccessfull"]) để chúng khớp với tệp php của bạn
Marco Weber

0

Swift có một loại suy luận mạnh mẽ. Hãy loại bỏ "nếu để" hoặc "bảo vệ cho phép" luồn lách và buộc mở khóa bằng cách sử dụng phương pháp chức năng:

  1. Đây là JSON của chúng tôi. Chúng tôi có thể sử dụng JSON tùy chọn hoặc thông thường. Tôi đang sử dụng tùy chọn trong ví dụ của chúng tôi:

    let json: Dictionary<String, Any>? = ["current": ["temperature": 10]]
  1. Chức năng trợ giúp. Chúng ta chỉ cần viết chúng một lần và sau đó sử dụng lại với bất kỳ từ điển nào:

    /// 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. Và đây là phép thuật của chúng tôi - trích xuất giá trị:

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

Chỉ cần một dòng mã và không ép buộc hoặc đúc kiểu thủ công. Mã này hoạt động trong sân chơi, vì vậy bạn có thể sao chép và kiểm tra nó. Đây là một triển khai trên GitHub.


0

Đây là một cách khác để giải quyết vấn đề của bạn. Vì vậy, vui lòng kiểm tra giải pháp dưới đây. Hy vọng nó sẽ giúp bạn.

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

Vấn đề là với phương thức tương tác API. Phân tích cú pháp JSON chỉ được thay đổi theo cú pháp. Vấn đề chính là cách lấy dữ liệu. Những gì bạn đang sử dụng là một cách đồng bộ để có được dữ liệu. Điều này không hoạt động trong mọi trường hợp. Những gì bạn nên sử dụng là một cách không đồng bộ để tìm nạp dữ liệu. Theo cách này, bạn phải yêu cầu dữ liệu thông qua API và chờ nó phản hồi với dữ liệu. Bạn có thể đạt được điều này với phiên URL và thư viện bên thứ ba như thế nào Alamofire. Dưới đây là mã cho phương pháp Phiên 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"
      }
     }
   ]
}

Nếu tôi tạo mô hình bằng json trước Sử dụng liên kết này [blog]: http://www.jsoncafe.com để tạo cấu trúc có thể mã hóa hoặc bất kỳ định dạng nào

Mô hình

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

Phân tích

    do {
        let res = try JSONDecoder().decode(RootClass.self, from: data)
        print(res?.user?.first?.firstUser?.name ?? "Yours optional value")
    } catch {
        print(error)
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.