2017-08-29 37 views
7

Vì vậy, tôi có một tuyến API trả về một mảng các đối tượng JSON. Ví dụ:Swift 4 Codable Array's

[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 

Tôi đang cố gắng hình dung cách sử dụng tính năng có thể mã hóa mới trong Swift để chuyển đổi chúng thành hai đối tượng trong một lớp. Vì vậy, nếu tôi có một lớp người có khả năng mã hóa, tôi muốn nhận câu trả lời đó và cho tôi hai đối tượng người.

Tôi cũng đang sử dụng Alamofire để xử lý các yêu cầu.

Làm thế nào tôi có thể làm điều này? Cho đến nay tất cả mọi thứ tôi đã nhìn thấy liên quan đến các công cụ mã hóa chỉ cho phép 1 đối tượng. Và tôi đã không thấy bất kỳ sự tích hợp nào với Alamofire hoặc một khung công tác web.

+1

là câu hỏi của bạn như thế nào để chuyển đổi JSON bạn cung cấp vào một mảng of Person (thực thể ví dụ)? Hoặc một mảng của các đối tượng không đồng nhất? – nathan

+0

Vâng, tôi biết nếu tôi có '{" firstname ":" Tom "," lastname ":" Smith "," age ": 31}' và một lớp người tôi có thể chuyển đổi JSON thành đối tượng người trong Swift bằng cách sử dụng mã hoá . Nhưng tôi không chắc làm thế nào tôi có thể làm điều đó nếu tôi có mảng JSON mà tôi nhận được từ Alamofire. –

+0

Tôi không thực sự quen thuộc với Alamofire (hoặc với thư viện này), nhưng có https://github.com/Otbivnoe/CodableAlamofire –

Trả lời

7

Alamofire sẽ không thêm hỗ trợ Codable ngay bây giờ (xem #2177), bạn có thể sử dụng tiện ích này thay thế: https://github.com/Otbivnoe/CodableAlamofire.

let jsonData = """ 
[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 
""".data(using: .utf8)! 

struct Person: Codable { 
    let firstName, lastName: String 
    let age: Int 

    enum CodingKeys : String, CodingKey { 
     case firstName = "firstname" 
     case lastName = "lastname" 
     case age 
    } 
} 

let decoded = try! JSONDecoder().decode([Person].self, from: jsonData) 

mẫu: http://swift.sandbox.bluemix.net/#/repl/59a4b4fad129044611590820

Sử dụng CodableAlamofire:

let decoder = JSONDecoder() 
Alamofire.request(url).responseDecodableObject(keyPath: nil, decoder: decoder) { (response: DataResponse<[Person]>) in 
    let persons = response.result.value 
    print(persons) 
} 

keypath tương ứng với đường dẫn nơi các kết quả được chứa trong cấu trúc JSON. Ví dụ:

{ 
    "result": { 
     "persons": [ 
      {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
      {"firstname": "Bob", "lastname": "Smith", "age": 28} 
     ] 
    } 
} 

keypath =>results.persons

[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 

keypath =>nil (trống keypath ném một ngoại lệ)

+0

Vì vậy, nó sẽ hoạt động nếu 'jsonData' giống như một mảng? –

+1

Đã cập nhật câu trả lời. Hãy xem mã mẫu – nathan

+0

Câu trả lời rất chi tiết. Cảm ơn nhiều. Không có thời gian để xem xét tất cả bây giờ nhưng sẽ nhận được vào nó tại một số điểm. Cám ơn rất nhiều!!! –

0

tôi quản lý để serialize phản ứng dữ liệu với các đối tượng codable.

Vì tất cả các bạn có thể đã quen thuộc với việc chuyển đổi đối tượng json [String: String] chẳng hạn. Đối tượng json đó cần phải được chuyển đổi thành Data bằng cách sử dụng json.data(using: .utf8)!.

Với Alamofire, nó rất dễ dàng để có được dữ liệu (hoặc ít nhất là loại dữ liệu này làm việc cho tôi, đã tương thích với .utf8 điều), tôi chỉ có thể sử dụng chức năng đã có sẵn này

func responseData(queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Data>) -> Void) -> Self 

Sau đó chỉ cần sử dụng dữ liệu đó như là đầu vào cho Decoder trong completionHandler

let objek = try JSONDecoder().decode(T.self, from: data) 

Bạn cũng có thể làm điều này với một số chức năng serialization chung chung, với một tinh chỉnh nhỏ, từ các tài liệu

Generic Response Object Serialization

để sửa đổi này

func responseCodable<T: Codable>(
    queue: DispatchQueue? = nil, 
    completionHandler: @escaping (DataResponse<T>) -> Void) 
    -> Self 
{ 
    let responseSerializer = DataResponseSerializer<T> { request, response, data, error in 
     guard error == nil else { return .failure(BackendError.network(error: error!)) } 

     guard let data = data else { 
      return .failure(BackendError.objectSerialization(reason: "data is not valid")) 
     } 


     do{ 
      let objek = try JSONDecoder().decode(T.self, from: data!) 
      return .success(objek) 
     } catch let e { 
      return .failure(BackendError.codableSerialization(error: e)) 
     } 

    } 

    return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) 
} 

mẫu struct

struct Fids: Codable { 

    var Status: Status? 
    var Airport: Airport? 
    var Record: [FidsRecord] 
} 

Sử dụng chức năng theo cách này

Alamofire.request("http://whatever.com/zzz").responseCodable { (response: DataResponse<Fids>) in 
     switch response.result{ 
     case .success(let value): 
      print(value.Airport) 
     // MARK: do whatever you want 
     case .failure(let error): 
      print(error) 
      self.showToast(message: error.localizedDescription) 
     } 
    } 
+0

Điều gì là duy nhất về câu trả lời của bạn so với câu trả lời được chấp nhận? –

+0

bạn không cần phần mở rộng hoặc bất kỳ thứ gì. Tôi có nghĩa là nó rất dễ dàng chỉ để sử dụng phản ứng dữ liệu, từ chức năng hiện có. Thay thế đơn giản cho những người đã sử dụng Alamofire trong thời gian dài. Đúng? – abbawssdsad

+0

Vâng. Sau khi nghiên cứu thêm, có nhiều cách tốt hơn để xử lý vấn đề này. Thêm responseCodable Tôi cảm thấy như chỉ cần thêm độ phức tạp. Tôi cũng cho rằng câu hỏi chính của tôi là về Swift 4 Codable Arrays. Không phải Alamofire. Mặc dù tôi đã đề cập đến Alamofire đó không phải là câu hỏi chính của tôi. –

Các vấn đề liên quan