2017-08-29 13 views
7

Tak więc mam trasę API, która zwraca tablicę JSON obiektów. Na przykład:Swift 4 Codable Array's

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

Próbuję wyobrazić sobie, jak korzystać z nowych funkcji do kodowania w systemie SWIFT dla konwersji do tych dwóch obiektów w klasie. Więc jeśli mam klasę osób, która jest kodowalna, chciałbym wziąć tę odpowiedź i zlecić mi dwie osoby.

Używam również Alamofire do obsługi żądań.

Jak mogę to zrobić? Do tej pory wszystko, co widziałem, związane z kodowaniem, pozwala tylko na 1 obiekt. I nie widziałem żadnej integracji z Alamofire lub ramą internetową.

+1

Czy Twoje pytanie jak przekształcić JSON podanych w tablica osoby (przykład podmiotu)? Lub tablica heterogenicznych obiektów? – nathan

+0

Wiem, że jeśli mam '{" firstname ":" Tom "," lastname ":" Smith "," age ": 31}' i klasa osoby, którą mogę przekonwertować JSON na obiekt osoby w Swift przy użyciu kodowalnej . Ale nie jestem pewien, jak mogę to zrobić, jeśli mam taką tablicę JSON, którą otrzymuję od Alamofire. –

+0

Nie jestem zaznajomiony z Alamofire (lub z tą biblioteką), ale jest https://github.com/Otbivnoe/CodableAlamofire –

Odpowiedz

7

Alamofire nie doda do tej pory funkcji Codable (patrz #2177), zamiast tego możesz użyć tego rozszerzenia: 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) 

próbki: http://swift.sandbox.bluemix.net/#/repl/59a4b4fad129044611590820

Stosując CodableAlamofire:

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

keypath odpowiada ścieżce Wyniki są zawarte w strukturze JSON. Na przykład:

{ 
    "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 (pusty keypath zgłasza wyjątek)

+0

Więc to zadziała, jeśli 'jsonData' jest jak tablica? –

+1

Odpowiedź zaktualizowana. Zajrzyj do przykładowego kodu – nathan

+0

Bardzo szczegółowa odpowiedź. Dziękuję Ci bardzo. Nie mam dość czasu, aby przejrzeć to wszystko teraz, ale dojdzie do tego w pewnym momencie. Dzięki wielkie!!! –

0

udało mi się szeregować dane odpowiedzi na możliwym do kodowania obiektów.

Jak wszyscy mogliście być obeznani na przykład z konwersją obiektu Json [String: String]. Ten obiekt Json należy przekonwertować na Data, używając json.data(using: .utf8)!.

Z Alamofire, nie jest łatwo dostać się, że dane (lub przynajmniej tego rodzaju danych, pracował dla mnie, już kompatybilny z .utf8 rzeczy), mogę tylko korzystać z tego już dostępnych funkcji

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

Następnie wystarczy wykorzystać te dane jako dane wejściowe dla Decoder w completionHandler

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

można również zrobić to w pewnym rodzajowe funkcji serializacji, z trochę uszczypnąć, z dokumentacji

Generic Response Object Serialization

do tej modyfikacji

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

struct Próbka

struct Fids: Codable { 

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

Użyj funkcji tędy

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

Co jest wyjątkowego w Twojej odpowiedzi w porównaniu z odpowiedzią, która została zaakceptowana? –

+0

nie potrzebujesz rozszerzenia ani niczego. Chodzi mi o to, że bardzo łatwo jest użyć odpowiedzi na dane z istniejącej funkcji. Prosta alternatywa dla osób, które już od dawna używają Alamofire. Dobrze? – abbawssdsad

+0

Tak. Po przeprowadzeniu dalszych badań istnieją lepsze sposoby radzenia sobie z tym. Dodawanie responseCodable Czuję, że po prostu dodaje złożoności. Twierdzę również, że moje główne pytanie dotyczyło tablic kodowych Swift 4. Nie Alamofire. Chociaż wspomniałem o Alamofire, nie było to moje główne pytanie. –

Powiązane problemy