Swift下面字典(json)和模型的转换
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift下面字典(json)和模型的转换相关的知识,希望对你有一定的参考价值。
参考技术A 在OC下面字典和模型的转换有些非常好用的第三方框架,如(YYMode, MJExtension等),当然Swift也可以借鉴这两个框架,只是需要创建模型的时候继承自NSObject,并且加上关键字@objcMembers既可。1、在用原生Codable协议的时候,需要当前类继承协议Codable,只是swift的枚举、结构体和类都可以继承该协议。这点事OC无法做到的。
2、在使用Codable协议的时候,一定要确保模型和原始json数据之间的key值的一致性。
列入有一段json字典如下(这里我用的字典)
那么你的模型就需要如下实现(当然这是理想状态)
3、如果你的模型里面有一个字段如(name_op)并且原始json数据里面没有该值,此时你的模型如果如下。
那么你解析成模型的时候会失败,此时需要把不确定的值定义为可选类型。那么不管原始json数据有没有这个字段,都可以解析成功,如果没有,那么该属性为nil。
4、如果你的模型已经设计好了,但是原始json数据里面有个字段和你的字段事冲突的(如你的属性叫 nick 而原始数据为 nick_name ),那么该值是解析不成功的,如果是可选还好,至少能成功,否则就失败。
解决的办法是实现 enum CodingKeys: String, CodingKey 这个映射关系
5、如果你的模型里面带有嵌套关系,比如你的模型里面有个其他模型或者模型数组,那么只要保证嵌套的模型里面依然实现了对应的协议,和当前模型一样即可。
6、如果模型里面和原始数据里面的类型不统一,那么这个解析也会以失败告终。而这种情况需要自定义一个类去适配当前属性。最常见的有(Bool和Int,Int和String)这些在后台若类型语言上是不加区分的。所以不确定到底是什么类型,如果随意定义一个那么会失败。
如下:定义了一个可能是Bool或者Int的类型
下面是一个Int 或者String类型的
在设计模型的时候,如下赋值
若是完成上面几步,基本可以解决字典模型转换的巨大部分问题。贴上我设计的模型。
以及创建的字典
使用
swift:将传入的 json 数组转换为字典和对象
【中文标题】swift:将传入的 json 数组转换为字典和对象【英文标题】:swift: cast incoming json array to dictionary and object 【发布时间】:2014-10-18 18:34:23 【问题描述】:我正在玩弄/学习 Swift 和 JSON atm,但在正确转换我的响应时遇到了问题。
所以,我想要实现的是通过 Alamofire 请求显示“帖子”列表。我在显示“第一级”json 项目(如 post-ID 或“消息”)时没有问题,但是当涉及到作者数组时,我有点迷路了。
json 响应以没有名称的数组形式出现,因此第一个 [
[
-
__v: 1,
_id: "54428691a728c80424166ffb",
createDate: "2014-10-18T17:26:15.317Z",
message: "shshshshshshshhshshs",
-author: [
-
_id: "54428691a728c80424166ffa",
userId: "543270679de5893d1acea11e",
userName: "foo"
]
这是我对应的VC:
Alamofire.request(.GET, "\(CurrentConfiguration.serverURL)/api/posts/\(CurrentConfiguration.currentUser.id)/newsfeed/\(CurrentConfiguration.currentMode)",encoding:.JSON)
.validate()
.responseJSON (request, response, jsonData, error) in
let JSON = jsonData as? NSArray
self.loadPosts(JSON!)
tableView.delegate = self
tableView.dataSource = self
func loadPosts(posts:NSArray)
for post in posts
let id = post["_id"]! as NSString!
let message = post["message"]! as NSString!
var authorArray = post["author"]! as? [Author]!
println(authorArray)
var author:Author = Author()
author.userName = "TEST ME"
var postObj:Post = Post()
postObj.id = id
postObj.message = message
postObj.author = author
uppDatesCollection.append(postObj)
println(self.uppDatesCollection.count)
dispatch_async(dispatch_get_main_queue())
self.tableView.reloadData()
我的帖子模型
class Post
var id:String!
var message:String!
var createDate: NSDate!
var author:Array<Author>!
init ()
和作者
class Author
var id:String?
var userId:String?
var userName:String?
init ()
这里最好的方法是什么?您是否应该将返回的数组重新转换为字典,然后通过 .valueforkey 访问它?您是否以某种方式遍历数组以获取这些内容?
显然你不能说 author.name = authorArray[3] as String
【问题讨论】:
【参考方案1】:假设你有这样的Post
类:
class Post : Printable
var identifier:String!
var message:String!
var createDate: NSDate!
var authors:[Author]!
var description: String return "<Post; identifier = \(identifier); message = \(message); createDate = \(createDate); authors = \(authors)"
您的 JSON 中只有一个作者,但鉴于它似乎是 JSON 中的一个数组,我假设它也应该是对象模型中的一个数组,如上所示。 Author
类可以这样定义:
class Author : Printable
var identifier:String!
var userId:String!
var userName:String!
var description: String return "<Author; identifier = \(identifier); userId = \(userId); userName = \(userName)>"
我不知道为什么你隐含地解包了一些选项(使用!
定义)而其他没有(使用?
定义),所以我只是将它们全部隐含解包。根据您的业务规则进行调整。
另外,假设您的 JSON 看起来像这样(我不太确定您的问题中 JSON 中的 -
是什么,所以我清理了它并添加了第二位作者):
[
"__v": 1,
"_id": "54428691a728c80424166ffb",
"createDate": "2014-10-18T17:26:15.317Z",
"message": "shshshshshshshhshshs",
"author": [
"_id": "54428691a728c80424166ffa",
"userId": "543270679de5893d1acea11e",
"userName": "foo"
,
"_id": "8434059834590834590834fa",
"userId": "345903459034594355cea11e",
"userName": "bar"
]
]
那么解析它的例程可能如下所示:
func loadPosts(postsJSON: NSArray)
var posts = [Post]()
for postDictionary in postsJSON
let post = Post()
let createDateString = postDictionary["createDate"] as String
post.message = postDictionary["message"] as String
post.identifier = postDictionary["_id"] as String
post.createDate = createDateString.rfc3339Date()
if let authorsArray = postDictionary["author"] as NSArray?
var authors = [Author]()
for authorDictionary in authorsArray
let author = Author()
author.userId = authorDictionary["userId"] as String
author.userName = authorDictionary["userName"] as String
author.identifier = authorDictionary["_id"] as String
authors.append(author)
post.authors = authors
posts.append(post)
// obviously, do something with `posts` array here, either setting some class var, return it, whatever
这是我从String
到NSDate
的转换例程:
extension String
/// Get NSDate from RFC 3339/ISO 8601 string representation of the date.
///
/// For more information, see:
///
/// https://developer.apple.com/library/ios/qa/qa1480/_index.html
///
/// :returns: Return date from RFC 3339 string representation
func rfc3339Date() -> NSDate?
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return formatter.dateFromString(self)
【讨论】:
非常感谢您的回答!有没有更通用的方法来做到这一点,无论是板载的还是基于库的?通过迭代数组(我很乐意实现)来做到这一点,理论上我可以最终得到像 8x 嵌套的函数,这对我来说听起来很丑。 您当然可以按照这种方式做一些事情,但是如果没有看到一个展示此 JSON 的全部丰富性的示例,就很难说。您可能想在完全数据驱动和更实用的东西之间取得平衡。也许试一试,让我们知道你的情况。如果经过您的善意努力,您仍有疑问,请在此处发布新问题。以上是关于Swift下面字典(json)和模型的转换的主要内容,如果未能解决你的问题,请参考以下文章