2016-07-19 8 views
3

Ich benutze Argo in einer Swift-App, um JSON in Objekte zu dekodieren. Ich habe JSON wie folgt aus:Wie kann ich Unterklassen mit Argo und Swift erstellen?

"activities": [ 
    { 
    "id": "intro-to-the-program", 
    "type": "session", 
    "audio": "intro-to-the-program.mp3" 
    }, 
    { 
    "id": "goal-setting", 
    "type": "session", 
    "audio": "goal-setting.mp3" 
    }, 
    { 
    "id": "onboarding-quiz", 
    "type": "quiz" 
    } 
] 

Basierend auf dem ‚Typ‘, ich will eigentlich eine Unterklasse der Aktivitätsklasse instanziiert (Activity, ActivityQuiz etc.) und haben die Unterklasse ihre eigene Decodierung tun.

Wie kann ich das tun? Die Funktion decode() auf oberster Ebene erwartet einen Rückgabetyp von Decoded<Activity>, und keiner meiner Ansätze scheint es bisher zu bewerkstelligen.

Antwort

2

Hier ist eine Möglichkeit, wie Sie dies tun können, indem Sie den Typ einschalten, um ihn bedingt zu dekodieren und eine nette Fehlermeldung zu erhalten, wenn ein ungültiger Typ angegeben wird.

struct ThingWithActivities: Decodable { 
    let activities: [Activity] 

    static func decode(json: JSON) -> Decoded<ThingWithActivities> { 
    return curry(ThingWithActivities.init) 
     <^> json <|| "activities" 
    } 
} 

class Activity: Decodable { 
    let id: String 

    init(id: String) { 
    self.id = id 
    } 

    class func decode(json: JSON) -> Decoded<Activity> { 
    let decodedType: Decoded<String> = json <| "type" 
    return decodedType.flatMap { type in 
     switch type { 
     case "session": return ActivitySession.decode(json) 
     case "quiz": return ActivityQuiz.decode(json) 
     default: 
     return .Failure(.Custom("Expected valid type, found: \(type)")) 
     } 
    } 
    } 
} 

class ActivitySession: Activity { 
    let audio: String 

    init(id: String, audio: String) { 
    self.audio = audio 
    super.init(id: id) 
    } 

    override static func decode(json: JSON) -> Decoded<Activity> { 
    return curry(ActivitySession.init) 
     <^> json <| "id" 
     <*> json <| "audio" 
    } 

} 

class ActivityQuiz: Activity { 
    override static func decode(json: JSON) -> Decoded<Activity> { 
    return curry(ActivityQuiz.init) 
     <^> json <| "id" 
    } 
} 

let activities: Decoded<ThingWithActivities>? = JSONFromFile("activities").flatMap(decode) 
print(activities) 
// => Optional(Success(ThingWithActivities(activities: [ActivitySession, ActivitySession, ActivityQuiz]))) 

Der wichtigste Teil ist die Art herausziehen und .flatMap ing über sie bedingt in der Art entschlüsseln sollte es sein.

+0

Sie sind ein Genie - es funktioniert. Wow, dieser Swift-Malarkey ist sicherlich gewöhnungsbedürftig! –