【问题标题】:How can I create subclasses using Argo and Swift?如何使用 Argo 和 Swift 创建子类?
【发布时间】:2016-07-19 14:03:45
【问题描述】:

我在 Swift 应用程序中使用 Argo 将 JSON 解码为对象。我有这样的 JSON:

"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"
  }
]

基于“类型”,我实际上想实例化 Activity 类的子类(ActivitySession、ActivityQuiz 等)并让子类自己解码。

我该怎么做?顶级 decode() 函数期望返回类型为 Decoded<Activity>,到目前为止,我的任何方法似乎都无法击败它。

【问题讨论】:

    标签: swift argo


    【解决方案1】:

    这是一种方法,您可以通过打开类型来有条件地对其进行解码,并在给出无效类型时得到一个很好的错误消息。

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

    关键部分是提取类型并.flatMaping 以有条件地解码为应有的类型。

    【讨论】:

    • 您先生是个天才——它有效。哇这个 Swift malarkey 肯定需要一些时间来适应!
    猜你喜欢
    • 2014-10-13
    • 1970-01-01
    • 2021-02-24
    • 2021-01-05
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多