2016-05-10 48 views
4

Ich bin neu bei Swift und bin nicht in der Lage herauszufinden, wie ein JSON-Array zu einem Array von Swift-Objekten deserialisiert werden kann. Ich bin in der Lage, einen einzelnen JSON-Benutzer zu einem Swift-Benutzerobjekt zu deserialisieren, aber ich bin mir nicht sicher, wie ich das mit einem JSON-Benutzerfeld machen soll.Deserialisieren eines JSON-Arrays in ein Swift-Array von Objekten

Hier ist meine User.swift Klasse:

class User { 
    var id: Int 
    var firstName: String? 
    var lastName: String? 
    var email: String 
    var password: String? 

    init(){ 
     id = 0 
     email = "" 
    } 

    init(user: NSDictionary) { 
     id = (user["id"] as? Int)! 
     email = (user["email"] as? String)! 

     if let firstName = user["first_name"] { 
      self.firstName = firstName as? String 
     } 

     if let lastName = user["last_name"] { 
      self.lastName = lastName as? String 
     } 

     if let password = user["password"] { 
      self.password = password as? String 
     } 
    } 
} 

Hier ist die Klasse, wo ich die JSON deserialisieren bin versucht:

//single user works. 
Alamofire.request(.GET, muURL/user) 
     .responseJSON { response in 
       if let user = response.result.value { 
        var swiftUser = User(user: user as! NSDictionary) 
       } 
      } 

//array of users -- not sure how to do it. Do I need to loop? 
Alamofire.request(.GET, muURL/users) 
     .responseJSON { response in 
       if let users = response.result.value { 
        var swiftUsers = //how to get [swiftUsers]? 
       } 
      } 
+1

Warum verwenden Sie nicht ['AlamofireObjectMapper'] (https : //github.com/tristanhimmelmannman/AlamofireObjectMapper) Bibliothek? – ozgur

+0

Oh, ich hatte keine Ahnung, dass ich das benutzen könnte. Ich dachte, es wäre nur REST. Ich werde es versuchen. – Prabhu

+0

E-Mail ist auch ein Pflichtfeld für Benutzer. Ist es das beste Verfahren, es als Pflichtfeld in Swift zu belassen, oder wäre es besser, es zu einem Optional zu machen - falls der JSON aus irgendeinem Grund keinen Wert hat? – Prabhu

Antwort

2

Der beste Ansatz ist die Verwendung Allgemein Antwort Objekt Serialisierung von Alamofire hier ist ein Beispiel:

1) Fügen Sie die Erweiterung in Ihrem API Manager oder auf Aktualisieren eine separate Datei

public protocol ResponseObjectSerializable { 
     init?(response: NSHTTPURLResponse, representation: AnyObject) 
    } 

    extension Request { 
     public func responseObject<T: ResponseObjectSerializable>(completionHandler: Response<T, NSError> -> Void) -> Self { 
      let responseSerializer = ResponseSerializer<T, NSError> { request, response, data, error in 
       guard error == nil else { return .Failure(error!) } 

       let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments) 
       let result = JSONResponseSerializer.serializeResponse(request, response, data, error) 

       switch result { 
       case .Success(let value): 
        if let 
         response = response, 
         responseObject = T(response: response, representation: value) 
        { 
         return .Success(responseObject) 
        } else { 
         let failureReason = "JSON could not be serialized into response object: \(value)" 
         let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason) 
         return .Failure(error) 
        } 
       case .Failure(let error): 
        return .Failure(error) 
       } 
      } 

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

public protocol ResponseCollectionSerializable { 
    static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self] 
} 

extension Alamofire.Request { 
    public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: Response<[T], NSError> -> Void) -> Self { 
     let responseSerializer = ResponseSerializer<[T], NSError> { request, response, data, error in 
      guard error == nil else { return .Failure(error!) } 

      let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments) 
      let result = JSONSerializer.serializeResponse(request, response, data, error) 

      switch result { 
      case .Success(let value): 
       if let response = response { 
        return .Success(T.collection(response: response, representation: value)) 
       } else { 
        let failureReason = "Response collection could not be serialized due to nil response" 
        let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason) 
        return .Failure(error) 
       } 
      case .Failure(let error): 
       return .Failure(error) 
      } 
     } 

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

2) Ihr Modell Objekt wie folgt:

final class User: ResponseObjectSerializable, ResponseCollectionSerializable { 
    let username: String 
    let name: String 

    init?(response: NSHTTPURLResponse, representation: AnyObject) { 
     self.username = response.URL!.lastPathComponent! 
     self.name = representation.valueForKeyPath("name") as! String 
    } 

    static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [User] { 
     var users: [User] = [] 

     if let representation = representation as? [[String: AnyObject]] { 
      for userRepresentation in representation { 
       if let user = User(response: response, representation: userRepresentation) { 
        users.append(user) 
       } 
      } 
     } 

     return users 
    } 
} 

3), dann können Sie es so verwenden:

Alamofire.request(.GET, "http://example.com/users") 
     .responseCollection { (response: Response<[User], NSError>) in 
      debugPrint(response) 
     } 

Quelle: Generic Response Object Serialization

Nützlicher Link: Alamofire JSON Serialization of Objects and Collections

+1

Danke, werde es versuchen! – Prabhu

+1

Ich habe das in meinem letzten Projekt verwendet und finde es eine elegante Lösung, denn Mapping ist bereits ein Feature in Almofire, und es ist besser, nicht zu anderen Drittanbieter-Bibliothek zu verzögern, um Kompatibilitätsprobleme in der Zukunft zu vermeiden – Aladin

+0

Wie gehe ich damit um ein optionales Feld? Sag es war: Let name: String? – Prabhu

1

Ich würde sie durchlaufen und dann jeden Benutzer zu einem Array hinzufügen (vorzugsweise eine Eigenschaft der VC und keine Instanzvariable), aber hier ist ein Beispiel.

Alamofire.request(.GET, "YourURL/users") 
     .responseJSON { response in 

      if let users = response.result.value { 

       for user in users { 

        var swiftUser = User(user: user as! NSDictionary) 

        //should ideally be a property of the VC 
        var userArray : [User] 

        userArray.append(swiftUser) 
       } 
      } 
    } 
+0

Ich bin mir nicht ganz sicher, wie der JSON aus der Antwort aussieht, also müssen Sie ihn vielleicht ein wenig optimieren, aber das sollte Ihnen zumindest eine Idee geben. – Echizzle

+0

Mit dieser Methode erhalte ich eine Fehlermeldung, die besagt, dass Type AnyObject dem Protokoll SequenceType nicht entspricht. Irgendeine Idee was das ist? – Prabhu

+1

Versuchen Sie, die for-Schleife zu "für Benutzer in Benutzern als! [AnyObject]" anstatt nur "für Benutzer in Benutzern" zu ändern – Echizzle

1

Sie könnten auch versuchen, EVReflection https://github.com/evermeer/EVReflection Es ist noch einfacher, das heißt JSON (Code-Schnipsel aus EVReflection Link genommen) zu analysieren:

let json:String = "{ 
    \"id\": 24, 
    \"name\": \"Bob Jefferson\", 
    \"friends\": [{ 
     \"id\": 29, 
     \"name\": 
     \"Jen Jackson\"}]}" 

Sie diese Klasse verwenden können:

class User: EVObject { 
    var id: Int = 0 
    var name: String = "" 
    var friends: [User]? = [] 
} 

in auf diese Weise:

let user = User(json: json) 
Verwandte Themen