自定义对象数组的JSONSerialization

时间:2016-11-30 22:59:59

标签: ios swift nsjsonserialization

我有一个自定义类

public class Balance: NSObject {
   var details: String
   var date:    Date
   var amount:  Double
}

我尝试过作为结构而且作为一个类都失败

我有一系列余额list: [Balance]

现在我需要将此数组转换为JSON字符串

之类的东西
[ {details = "text"; date = "2016-11-20"; amount = 0;} ,
  {details = "text2"; date = "2016-11-25"; amount= 10;} ]

我还需要能够将String转换回数组。 但我甚至无法让数组到JSON字符串工作

var resStr = ""
var list: [Balance] 
do {
   let data = try JSONSerialization.data(withJSONObject: list,  options: .prettyPrinted)
   resStr   = String.init(data: data, encoding: .utf8) ?? ""
} catch { fatalError("Error BALANCE HISTORY ")  }

失败了  'JSON写入无效类型(余额)'

请指教 提前致谢

4 个答案:

答案 0 :(得分:1)

如何定义你的课程:

public class Balance: NSObject {
    var details: String
    var date:    Date
    var amount:  Double
    func toJSONString() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return "{details = \(self.details); date = \(dateFormatter.string(from: self.date)); amount = \(self.amount);}"
    }
}

然后你可以像这样创建完整的JSON字符串:

var fullJSONArray = [String]()
for balance in list {
    fullJSONArray.append(balance.toJSONString)
}
let fullJSONString = fullJSONArray.description

我希望这会帮助你!祝你好运,如果你有任何进一步的问题或问题,请告诉我!

答案 1 :(得分:1)

您只能将非常小的数据类型列表存储到JSON。

@CoolPenguin提供了一种解决方案 - 一种将对象转换为JSON字符串的自定义方法。

我建议不要自己构建JSON字符串。

相反,我建议为您的类创建toDictionary()方法,并使用init(dictionary:)方法从字典中创建Balance对象。

您可以将日期转换为自1970年以来的TimeInterval(UNIX"纪元日期"。)这似乎比将它们转换为日期字符串更容易。

然后,您可以将Balance个对象数组映射到字典数组,并使用普通JSONSerialization那个转换为JSON。

let mappedArray = balanceArray.map{$0.toDictionary()}

然后轻松将您的词典数组转换为JSON。

答案 2 :(得分:1)

既然其他人指出首先将对象转换为 Dictionary 就可以达到预期的效果,那么我将提供一种方法来使用 JSONEncoder 来实现所需的效果。

如果您维护需要在 JSON 编码字符串中表示的值(例如 date 作为格式化的 String),唯一需要的位是,

  • 使您的类型符合Codable
  • 创建一个 CodingKeys 枚举,代表您的类型属性的 JSON 键。

请参阅以下适用于您的对象的示例。

public class Balance: NSObject, Codable {
    var details: String
    // Used to represent formatted date.
    var dateString: String
    var date:    Date = Date(){
        didSet{
            updateDateString()
        }
    }
    var amount:  Double

    enum CodingKeys: String, CodingKey{
        case details, dateString, amount
    }
    
    init(_ d: String, amt: Double){
        details = d
        dateString = ""
        date = Date()
        amount = amt
        
        super.init()
        updateDateString()
    }
    
    private func updateDateString(){
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "yyyy-MM-dd"
        dateString = df.string(from: date)
    }
}

var arr: [Balance] = [
    Balance("Shared Balance", amt: 100),
    Balance("Coupon Balance", amt: 120),
    Balance("Account Balance", amt: 150)
]

do{
    let data = try JSONEncoder().encode(arr)

    // Convert to JSON Encoded String
    let str = String(data: data, encoding: .utf8)!
    print(str)
    
    // Convert back from JSON Encoded String
    let raw = try JSONDecoder().decode([Balance].self, from: str.data(using: .utf8)!)
    print(raw)
}
catch(let err){
    print(err)
}

额外的 updateDateString() 样板代码用于生成日期格式为 "yyyy-MM-dd" 的字符串。

上述代码可以生成 Balance 数组的 JSON 编码版本,如下所示。

[{"details":"Shared Balance","amount":100,"dateString":"2021-01-14"},
{"details":"Coupon Balance","amount":120,"dateString":"2021-01-14"},
{"details":"Account Balance","amount":150,"dateString":"2021-01-14"}]

关键是使用 JSONEncoder 而不是 JSONSerialization

希望我有所帮助!

答案 3 :(得分:0)

嗯,我相信你首先需要将你的对象转换成某种形式的字典。

让我举个例子:

class Balance: NSObject {
    var details: String
    var date: Date
    var amount: Double

    func asDictionary() -> [String: AnyObject] {
        return ["details": details as AnyObject, "date": "\(date)" as AnyObject, "amount": amount as AnyObject]
    }
}

使用方法asDictionary将对象转换为字典,以便将其序列化为JSON。

假设您有一个Balance对象列表。

您需要首先使用上述方法将每个对象转换为字典,然后尝试将对象序列化为JSON。请注意,该列表现在是[String:AnyObject]词典的列表,而不是Balance对象列表。

var resStr = ""

var list: [[String: AnyObject]] = [balance1.asDictionary(), balance2.asDictionary()] 
do {
   let data = try JSONSerialization.data(withJSONObject: list,  options: .prettyPrinted)
   resStr   = String.init(data: data, encoding: .utf8) ?? ""
} catch { fatalError("Error BALANCE HISTORY ")  }

对于某些类型,比如日期字段,您需要找到一些方法将其转换为String,因为JSONSerializer非常挑剔。在这种情况下,我只使用字符串插值,但格式可能不是您想要的样式。

如果要从JSON转换回Balance对象,首先需要将JSON转换为字典,然后检查每个字段是否存在,如果存在,则构造您的Balance对象。

假设您已将JSON数据转换为名为dict的变量中的字典,您可以执行以下操作:

// supposing you have a single object in dict
var balance: Balance
balance.details = dict["details"]
balance.amount = dict["amount"]
balance.date = parseDate(dict["date"])

假设您有一个函数parseDate,用于将String中的日期解析为Date对象。

您可以在此处查看将字符串日期转换为对象:Use SwiftyJSON to deserialize NSDate