2014-12-07 18 views
5

Verwandte Frage mit: Generic completion handler in SwiftEXC_BAD_ACCESS Generics in Swift

In einer Swift App Ich schreibe, ich bin das Herunterladen JSON und ich möchte es in Modellobjekte konvertieren. Gerade jetzt, ich mache das so:

func convertJSONData<T: Entity>(jsonData: NSData?, jsonKey: JSONKey, _: T.Type) -> [T]? { 
     var entities = [T]() 
     if let data = jsonData { 

      // Left out error checking for brevity 

      var json = JSON(data: data, options: nil, error: nil) 
      var entitiesJSON = json[jsonKey.rawValue] 

      for (index: String, subJson: JSON) in entitiesJSON { 

       // Error: EXC_BAD_ACCESS(code=EXC_I386_GPFLT) 

       let entity = T(json: subJson) 
       entities.append(entity) 
      } 
     } 
     return entities 
    } 

Jedes Objekt konform Entity Geräte init(json: JSON). JSON ist ein Typ, der in der -Bibliothek definiert ist. Das ist auch der Grund, warum die Aufzählung ein bisschen komisch aussieht.

Ich nenne convertJSONData() in dieser Methode:

public func performJSONRequest<T where T: Entity>(jsonRequest: JSONRequest<T>) { 
     var urlString = ... 
     Alamofire.request(.GET, urlString, parameters: nil, encoding: .JSON).response { (request, response, data, error) -> Void in 
       var books = self.convertJSONData(data as? NSData, jsonKey: jsonRequest.jsonKey, T.self) 
       jsonRequest.completionHandler(books, error) 
     } 
    } 

ich einen Laufzeit EXC_BAD_ACCESS(code=EXC_I386_GPFLT) Fehler bekommen Aufruf T(json: subJSON). Es gibt keine Compiler-Warnungen oder Fehler. Obwohl ich die Fehlerüberprüfung im obigen Code ausgelassen habe, gibt es eine Fehlerüberprüfung im tatsächlichen Code und error ist Null.

Ich bin mir nicht sicher, ob dies ein Compiler Bug oder meine Schuld ist und jede Hilfe, die das herauszufinden, wird sehr geschätzt.

+0

Ist die Klasse Entity und die 'init' öffentlichen oder lokalen das Projekt? –

+0

Es ist eigentlich ein Protokoll, markiert als "öffentlich". Protokollmethoden können nicht als 'public' markiert werden, aber da 'Entity' selbst ist, sehe ich nicht, wie das das Problem verursachen könnte. – wander

+0

Welchen Typ meldet der Debugger für 'entitiesJSON'? –

Antwort

3

Mehrere Dinge gehen hier vor, und ich vermute, das Problem liegt irgendwo im Initialisierer der Klasse, die das Entity Protokoll implementiert.

den Code Unter der Annahme, ähnelt dem folgenden:

protocol Entity { 
    init(json: JSON) 
} 

class EntityBase: Entity { 
    var name: String = "" 
    required init(json: JSON) { // required keyword is vital for correct type inference 
     if let nameFromJson = json["name"].string { 
      self.name = nameFromJson 
     } 
    } 

    func getName() -> String { return "Base with \(name)" } 
} 

class EntitySub: EntityBase { 
    convenience required init(json: JSON) { 
     self.init(json: json) // the offending line 
    } 

    override func getName() -> String { return "Sub with \(name)" } 
} 

Der Code kompiliert mit self.init(json: json) in der Unterklasse, sondern tatsächlich versucht, die Instanz die bequeme Methode führt zu einem EXC_BAD_ACCESS zu initialisieren.

Entweder den Initialisierer der Unterklasse entfernen oder einfach required init implementieren und super aufrufen.

class EntitySub: EntityBase { 
    required init(json: JSON) { 
     super.init(json: json) 
    } 

    override func getName() -> String { return "Sub with \(name)" } 
} 


Verfahren die jsonData zu einem Entity zu konvertieren (modifizierte speziell leicht .None zurückzukehren, wenn jsonDatanil ist):

func convertJSONData<T:Entity>(jsonData: NSData?, jsonKey: JSONKey, type _:T.Type) -> [T]? { 
    if let jsonData = jsonData { 
     var entities = [T]() 

     let json = JSON(data: jsonData, options:nil, error:nil) 
     let entitiesJSON = json[jsonKey.rawValue] 

     for (index:String, subJson:JSON) in entitiesJSON { 

      let entity:T = T(json: subJson) 

      entities.append(entity) 

     } 

     return entities 
    } 

    return .None 
} 
+0

Ich bin nicht Unterklassen, und ich benutze 'struct's. Ich habe einen kleinen Text gemacht, der den Code zeigt, den ich habe. Es ist wirklich so einfach. https://gist.github.com/wandersiemers/cb3d486c7d370d35eeab – wander

+0

im 'init (json: JSON)' vor dem Aufruf von 'init (id: Int, name: String)' ziehe die Werte in die Eigenschaften und überspringe den Aufruf von ' selbst.init'. Sollte Ihnen die Möglichkeit geben, ein Problem mit den JSON-Daten zu identifizieren, falls vorhanden. –

+1

Es stürzt ab, bevor sogar die erste Zeile der eigentlichen Implementierung von 'init (json: JSON)' erreicht wird. Ich würde denken, dass etwas nicht stimmt mit dem, was der Compiler denkt, ist der tatsächliche Typ, den T darstellt, aber ich kann * warum * nicht herausfinden. – wander