ValueTransformer

ValueTransformer如其名,就是进行值转换的,将一个数据结构转换为另外的数据结构,比如当后台传入模型与显示模型存在较大差异时使用。

ValueTransformer类介绍

本身是一个抽象类,用来进行值转换,使用的时候需要继承创建子类实现其方法。

转换器基本信息方法

向外部传递基本的转换结果类型, 是否允许反转等,注意是类方法哟。

    /// 转换输出类型类
    open class func transformedValueClass() -> AnyClass
	/// 是否允许反转, 默认是true, 如果重写的时候也设置为允许,则应该实现对应反转方法
    open class func allowsReverseTransformation() -> Bool

值转换实现方法

转换方法内部应该实现自定义转换和返回。

	/// 转换方法实现
	 open func transformedValue(_ value: Any?) -> Any?
	/// 反转方法实现
     open func reverseTransformedValue(_ value: Any?) -> Any?

基于命名注册与使用

	/// 实际使用
	 open class func setValueTransformer(_ transformer: ValueTransformer?, forName name: NSValueTransformerName)

官网使用实例:

class ClassNameTransformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        return NSString.self
    }
    
    override class func allowsReverseTransformation() -> Bool {
        return false
    }
    
    override func transformedValue(_ value: Any?) -> Any? {
        return (value as AnyObject).className
    }
}

extension NSValueTransformerName {
    static let classNameTransformerName = NSValueTransformerName(rawValue: "ClassNameTransformer")
}
/// 注册
ValueTransformer.setValueTransformer(ClassNameTransformer(), forName: .classNameTransformerName)
/// 实例化 [以下是笔者自行添加]
let transformer = ValueTransformer(forName: .classNameTransformerName)
/// 实际转换
let transformerValue = trnsformer.transformedValue(xxx)

实际应用

订单详情后台模型转为数组模型
比如,现在有一个订单详情页面如下:
在这里插入图片描述
后台返回数据格式如下:

{
  "amount": 2,
  "status": 1,
  "statusName": "待支付",
  "account": 20198978977,
  "time": "2019-12-12",
  "payFee": 100,
  "discountFee": 10,
  "payTypeName": "支付宝支付",
  "orderNo": "239810678"
}

常规做法
最基本的做法是,创建一个对应后台的模型,使用storyboard逐个添加label,然后映射代码赋值。
可扩展和数据驱动性方案
但是。。。。but, 这个页面现在是这样,那以后了,万一明天需求大大又需要增加一行了,如果数据源上着手了。这个时候就很容易想到UITableView + 数组驱动,一行就相当于一个cell,原谅我们项目里万物页面皆可TableView。
那么问题来了,后台返回的数据格式就不能满足要求,这个时候就可以转换器将后台模型转为数组,这样如果后期增加减少行,只需要在转换器中操作即可,这个转换器就达到了中间操作层作用。

后台模型

struct OrderInfoModel: Codable {
    var amount: Int = 0
    /// 订单状态
    var status: Int = 0
    var statusName: String = ""
    var account: Int = 0
    /// 支付时间
    var time: String = ""
    var payFee: Double = 0
    /// 优惠价格
    var discountFee: Double = 0
    var payTypeName: String = ""
    var orderNo: String = ""
}

Transformer文件

typealias OrderInfoItem = (title: String, content: String)

class OrderInfoTansformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        return OrderInfoItem.self as! AnyClass
    }
    override class func allowsReverseTransformation() -> Bool {
        /// 这里没有反转需求,所以设置为false
        return false
    }
    /// 将OrderInfo
    override func transformedValue(_ value: Any?) -> Any? {
        guard let model = value as? OrderInfoModel else {
            return nil
        }
        let dataSource: [(title: String, content: String)] = [
            ("订单号:", model.orderNo),
            ("订单状态",model.status == 1 ? "待付款" :"待使用"),
            ("支付方式", model.payTypeName),
            ("支付价格","\(model.payFee)")]
        return dataSource
    }
    //这里我不需要反转
//    override func reverseTransformedValue(_ value: Any?) -> Any? {
//
//    }
}

extension NSValueTransformerName {
    static let orderInfo = NSValueTransformerName("OrderInfoTansformer")
}

实际转换使用

private func transformer() {
        let decoder = JSONDecoder()
        let orderInfo = try! decoder.decode(OrderInfoModel.self, from: orderInfoJson.data(using: .utf8)!)
        // 先注册
        ValueTransformer.setValueTransformer(OrderInfoTansformer(), forName: .orderInfo)
        // 实例化
        let transformer = ValueTransformer(forName: .orderInfo)
        // 实际转换
        if let dataSource = transformer?.transformedValue(orderInfo) {
            print("转换成功\n\(dataSource)")
        }
    }

最后打印结果:

转换成功
(
    "(title: \"\U8ba2\U5355\U53f7\Uff1a\", content: \"239810678\")",
    "(title: \"\U8ba2\U5355\U72b6\U6001\", content: \"\U5f85\U4ed8\U6b3e\")",
    "(title: \"\U652f\U4ed8\U65b9\U5f0f\", content: \"\U652f\U4ed8\U5b9d\U652f\U4ed8\")",
    "(title: \"\U652f\U4ed8\U4ef7\U683c\", content: \"100.0\")"
)

自定义结构转换

在使用了ValueTransformer之后,我觉得诶,有点麻烦,其实核心代码在transformedValue()方法中。我为什么要定义一个类了。于是想想能不能给他用泛型来搞定。
操刀
定义转换结构体
注意这个结构体是通用的,实现转换的地方只需要关心闭包。

// 转换类型
struct Transformer<Old,New> {
    let closure: (Old) -> New
    func valueTransformer(old: Old) -> New {
        return closure(old)
    }
}

在Model或者ViewModel或者任何你喜欢的地方补全转换方法。我这里直接在model添加一个计算属性。
这里相当于ValueTransformer的自定义类转换过程,但是代码量会少很多

typealias OrderItem = (title: String, content: String)  // 别名一下枚举,提高代码简洁可读性。
struct OrderInfoModel: Codable { 
	...
	 var transformerToTuple: [OrderItem] {
        let transformer = Transformer<OrderInfoModel,[OrderItem]> {
            oleValue ->  [OrderItem] in
            // 转换过程
           let dataSource: [OrderItem] = [
                   ("订单号:", oleValue.orderNo),
                   ("订单状态",oleValue.status == 1 ? "待付款" :"待使用"),
                   ("支付方式", oleValue.payTypeName),
                   ("支付价格","\(oleValue.payFee)")]
            return dataSource
        }
        return transformer.valueTransformer(old: self)
    }
}

具体使用的地方

 private func transformer() {
        let decoder = JSONDecoder()
        let orderInfo = try! decoder.decode(OrderInfoModel.self, from: testJson.data(using: .utf8)!)
        let dataSource = orderInfo.transformerToTuple  // 一句代码即可获得
        print(dataSource)
    }

有同学可能要问,垃圾,直接定义一个方法转换不就完了吗? 没任何问题,就像系统为啥要定义那么多类一样,就是想告诉你,你使用这个类大概是干什么,以后你的小伙伴见到Transformer就明白了,这里是进行模型变换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值