草庐IT

Swift-转模型HandyJSON

响彻天堂 2023-03-28 原文
  • 一 简介

  • 二 特性

  • 三 安装使用以及封装

  • 四 使用示例

一 简介

HandyJSON是一个用于Swift语言中的JSON序列化/反序列化库。

与其他流行的Swift JSON库相比,HandyJSON的特点是,它支持纯swift类,使用也简单。它反序列化时(把JSON转换为Model)不要求ModelNSObject继承(因为它不是基于KVC机制),也不要求你为Model定义一个Mapping函数。只要你定义好Model类,声明它服从HandyJSON协议,HandyJSON就能自行以各个属性的属性名为Key,从JSON串中解析值。

HandyJSON目前依赖于从Swift Runtime源码中推断的内存规则,任何变动我们将随时跟进。

二 特性

  • 序列化ModelJSON、从JSON反序列化Model
  • 自然地以Model的属性名称作为解析JSONKey,不需要额外指定
  • 支持Swift中大部分类型
  • 支持classstruct定义的Model
  • 支持自定义解析规则
  • 类型自适应,如JSON中是一个Int,但对应ModelString字段,会自动完成转化

三 安装使用以及封装

3.1 安装
我使用的是cocopod进行包引入管理,修改Prodfie文件,添加如下代码:

pod 'HandyJSON'

3.2 封装
为了方便我们项目中的使用,我们一般都会在做一层封装,方便库的以后升级替换,以及方便日常业务逻辑的处理

JsonUtil.swift
 
import UIKit
import HandyJSON
class JsonUtil: NSObject {
    /**
     *  Json转对象
     */
    static func jsonToModel(_ jsonStr:String,_ modelType:HandyJSON.Type) ->BaseModel {
        if jsonStr == "" || jsonStr.count == 0 {
            #if DEBUG
                print("jsonoModel:字符串为空")
            #endif
            return BaseModel()
        }
        return modelType.deserialize(from: jsonStr)  as! BaseModel
        
    }
    
    /**
     *  Json转数组对象
     */
    static func jsonArrayToModel(_ jsonArrayStr:String, _ modelType:HandyJSON.Type) ->[BaseModel] {
        if jsonArrayStr == "" || jsonArrayStr.count == 0 {
            #if DEBUG
                print("jsonToModelArray:字符串为空")
            #endif
            return []
        }
        var modelArray:[BaseModel] = []
        let data = jsonArrayStr.data(using: String.Encoding.utf8)
        let peoplesArray = try! JSONSerialization.jsonObject(with:data!, options: JSONSerialization.ReadingOptions()) as? [AnyObject]
        for people in peoplesArray! {
            modelArray.append(dictionaryToModel(people as! [String : Any], modelType))
        }
        return modelArray
        
    }
    
    /**
     *  字典转对象
     */
    static func dictionaryToModel(_ dictionStr:[String:Any],_ modelType:HandyJSON.Type) -> BaseModel {
        if dictionStr.count == 0 {
            #if DEBUG
                print("dictionaryToModel:字符串为空")
            #endif
            return BaseModel()
        }
        return modelType.deserialize(from: dictionStr) as! BaseModel
    }
    
    /**
     *  对象转JSON
     */
    static func modelToJson(_ model:BaseModel?) -> String {
        if model == nil {
            #if DEBUG
                print("modelToJson:model为空")
            #endif
             return ""
        }
        return (model?.toJSONString())!
    }
    
    /**
     *  对象转字典
     */
    static func modelToDictionary(_ model:BaseModel?) -> [String:Any] {
        if model == nil {
            #if DEBUG
                print("modelToJson:model为空")
            #endif
            return [:]
        }
        return (model?.toJSON())!
    }
    
}

说明:这里我封装了5个方法,Json转对象,Json数组对象字典对象对象JSON对象字典,基本覆盖了我们日常开发的常用操作,与这个工具类相对应的,还有一个公共的基础module

BaseModel.swift
 
import UIKit
import HandyJSON
class BaseModel: HandyJSON {
//    var date: Date?
//    var decimal: NSDecimalNumber?
//    var url: URL?
//    var data: Data?
//    var color: UIColor?
    
    required init() {}
    
    func mapping(mapper: HelpingMapper) {   //自定义解析规则,日期数字颜色,如果要指定解析格式,子类实现重写此方法即可
//        mapper <<<
//            date <-- CustomDateFormatTransform(formatString: "yyyy-MM-dd")
//
//        mapper <<<
//            decimal <-- NSDecimalNumberTransform()
//
//        mapper <<<
//            url <-- URLTransform(shouldEncodeURLString: false)
//
//        mapper <<<
//            data <-- DataTransform()
//
//        mapper <<<
//            color <-- HexColorTransform()
      }
}

说明:封装的基础model类。开发中,我们自定义的model继承此model即可省去了每次都要引入 “import HandyJSON”,以及每次都要实现“required init() {}”方法,子类如果要自定义解析规则,重写mapping方法即可

四 使用示例

基于以上封装的类我们实现几个示例做具体说明,主要有以下几个示例:

  • Json转模型 (常用)
  • Json数组转模型 (常用)
  • 字典转模型
  • 模型转Json
  • 模型转字典
  • json与嵌套的模型相互转换特殊类型字段转换,日期类型,数字类型,颜色
1. Json转模型 (常用)
JsonToModel.swift
 
import UIKit
class JsonToModel: BaseModel {
    var id :Int?
    var color:String?
    var name:String?
}
 fileprivate func jsonTomodel(){
        let jsonString = "{\"id\":12345,\"color\":\"black\",\"name\":\"cat\"}"
        let model:JsonToModel = JsonUtil.jsonToModel(jsonString,JsonToModel.self) as! JsonToModel
        print(model.name as Any)
        print(model.color as Any)
        print(model.id as Any)
    }

说明:调用jsonToModel(_ jsonStr:String,_ modelType:HandyJSON.Type),传入两个参数,第一个参数是要转换的Json字符串,第二个参数是要转换的model类的class,因为公共类中统一返回的都是BaseModel类型,所以这里要调用 as!转换成具体的子类类型。

2. Json数组转模型 (常用)
JsonArrayToModel.swift
 
import UIKit
class JsonArrayToModel: BaseModel {
    var name:String?
    var id :String?
}
//json数组转模型
    fileprivate func jsonArrayTomodel() {
        let jsonArrayString: String = "[{\"name\":\"Bob\",\"id\":\"1\"}, {\"name\":\"Lily\",\"id\":\"2\"}, {\"name\":\"Lucy\",\"id\":\"3\"}]"
        let cats = JsonUtil.jsonArrayToModel(jsonArrayString, JsonArrayToModel.self) as! [JsonArrayToModel]
        for model:JsonArrayToModel  in cats {
            print(model.name as Any)
        }
    }

说明:调用jsonArrayToModel(_ jsonArrayStr:String, _ modelType:HandyJSON.Type)传入两个参数,第一个参数是要转换的数组型Json字符串,第二个参数是要转换的model类的class,返回值是一个数组,因为公共类中统一返回的都是BaseModel类型,所以这里要调用as!转换成具体的子类类型数组。

3 字典转模型
import UIKit
class JsonToModel: BaseModel {
    var id :Int!
    var color:String?
    var name:String?
}
//字典转模型
    fileprivate func dicToModel() {
        var dict = [String: Any]()
        dict["id"] = 1.1
        dict["color"] = "hello"
        dict["name"] = "李四"
        let model:JsonToModel = JsonUtil.dictionaryToModel(dict,JsonToModel.self) as! JsonToModel
        print(model.name as Any)
        print(model.color as Any)
        print(model.id as Any)
    }

说明:调用dictionaryToModel(_ dictionStr:[String:Any],_ modelType:HandyJSON.Type),传入两个参数,第一个参数是要转换的字典对象,第二个参数是要转换的model类的class,因为公共类中统一返回的都是BaseModel类型,所以这里要调用as!转换成具体的子类类型。

4. 模型转Json
JsonToModel.swift
 
import UIKit
class JsonToModel: BaseModel {
    var id :Int!
    var color:String?
    var name:String?
}
//模型转json
    fileprivate func modelToJson() {
        let model:JsonToModel = JsonToModel()
        model.color = "red"
        model.id    = 100
        model.name  = "李四真"
        let modelTostring = JsonUtil.modelToJson(model)
        print(modelTostring)
    }

说明:调用modelToJson(_ model:BaseModel?),传入一个参数,传入一个module对象,返回值是一个JSON字符串

5. 模型转字典
JsonToModel.swift

import UIKit
class JsonToModel: BaseModel {
    var id :Int!
    var color:String?
    var name:String?
}
 //模型转字典
    fileprivate func modelTodiction() {
        let model:JsonToModel = JsonToModel()
        model.color = "red"
        model.id    = 100
        model.name  = "李四"
        let modelTostring = JsonUtil.modelToDictionary(model)
        print(modelTostring["name"] as Any)
        
    }

说明:调用modelToDictionary(_ model:BaseModel?)传入一个参数,传入一个module对象,返回值是一个字典对象,对于日常开发中,有时候后台只返回一个字段,比如返回一个成功信息字段,直接把返回的json串转换成一个字典即可,没必要再构建一个model去转换。

6. json与嵌套的模型相互转换
CombineModel.swift
 
import UIKit
class Composition:  BaseModel {
    var aInt:Int?
    var aString:String?
}
 
class CombineModel: BaseModel {
    var aInt:Int?
    var comp1:Composition?
    var comp2:[Composition] = []
    
}
//json与嵌套的模型相互转换
    fileprivate func jsonTocombilModel() {
        let model:CombineModel = CombineModel()
        model.aInt = 1001
        let posModel1 = Composition()
        posModel1.aInt = 1
        posModel1.aString = "赵六1"
        
        let posModel2 = Composition()
        posModel2.aInt = 2
        posModel2.aString = "赵六2"
        
        let posModel3 = Composition()
        posModel3.aInt = 3
        posModel3.aString = "赵六3"
        
        model.comp1 = posModel1
        model.comp2.append(posModel2)
        model.comp2.append(posModel3)
        
        let modeString = JsonUtil.modelToJson(model)
        print(modeString)
        
        let model2 = JsonUtil.jsonToModel(modeString, CombineModel.self)
        print(model2)
    }

说明:还是调用Json转模型,模型转Json的方法,本例子演示的是对象嵌套,对象里面可以嵌套对象,可以嵌套对象数组,平时我们开发经常遇到这种结构的Json串

7. 特殊类型字段转换,日期类型,数字类型,颜色
SpacialTypeModel.swift
 
import UIKit
import HandyJSON
class SpacialTypeModel: BaseModel {
    var date: Date?
    var decimal: NSDecimalNumber?
    var url: URL?
    var data: Data?
    var color: UIColor?
    
    override func mapping(mapper: HelpingMapper) {
        mapper <<< 
            date <-- CustomDateFormatTransform(formatString: "yyyy-MM-dd")
 
        mapper <<<
            decimal <-- NSDecimalNumberTransform()
 
        mapper <<<
            url <-- URLTransform(shouldEncodeURLString: false)
 
        mapper <<<
            data <-- DataTransform()
 
        mapper <<<
            color <-- HexColorTransform()
    }
 
}
// 特殊类型字段转换,日期类型,数字类型,颜色
    fileprivate func jsonToSpecialModel () {
        
        let object = SpacialTypeModel()
        object.date = Date()
        object.decimal = NSDecimalNumber(string: "1.23423414371298437124391243")
        object.url = URL(string: "https://www.aliyun.com")
        object.data = Data(base64Encoded: "aGVsbG8sIHdvcmxkIQ==")
        object.color = UIColor.blue
        
        let specailModelString = JsonUtil.modelToJson(object)
        print(object.toJSONString()!)
        // it prints:
        // {"date":"2017-09-11","decimal":"1.23423414371298437124391243","url":"https:\/\/www.aliyun.com","data":"aGVsbG8sIHdvcmxkIQ==","color":"0000FF"}
        
        let mappedObject:SpacialTypeModel = JsonUtil.jsonToModel(specailModelString, SpacialTypeModel.self) as! SpacialTypeModel
        print(mappedObject.date as Any)
    }

说明:本例演示的是对于对象里含有特殊类型字段的转换方法,主要注意点在构建model类里,我们要重写父类mapping方法还要引入HandyJSON头文件

有关Swift-转模型HandyJSON的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  6. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  9. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  10. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

随机推荐