zoukankan      html  css  js  c++  java
  • 【KakaJSON手册】04_JSON转Model_04_值过滤

    KakaJSON手册的第2篇文章中提过:由于JSON格式能表达的数据类型是比较有限的,所以服务器返回的JSON数据有时无法自动转换成客户端想要的数据类型

    • 比如客户端想要的是Date类型,服务器返回的可能是字符串"2018-08-08 08:08:08.888"或者"2018/08/08 08:08:08.888"
    • 像上述情况,KakaJSON内部是无法自动转换的,但提供了值过滤机制,允许开发者对JSON值进行自定义处理

    日期处理

    // 这2个DateFormatter仅仅为了举例子而写的,具体细节根据自己需求而定
    private let date1Fmt: DateFormatter = {
        let fmt = DateFormatter()
        fmt.dateFormat = "yyyy-MM-dd"
        return fmt
    }()
    
    private let date2Fmt: DateFormatter = {
        let fmt = DateFormatter()
        fmt.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
        return fmt
    }()
    
    struct Student: Convertible {
        var date1: Date?
        var date2: NSDate?
    
        // 实现kj_modelValue方法
        // 会传入属性`property`以及这个属性对应的JSON值`jsonValue`
        // 返回值是你希望最后设置到模型属性上的值
        // 如果返回`jsonValue`,代表不做任何事,交给KakaJSON内部处理
        // 如果返回`nil`,代表忽略这个属性,KakaJSON不会给这个属性设值(属性会保留它的默认值)
        func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
            switch property.name {
    
            // 如果jsonValue是字符串,就直接转成Date
            case "date1": return (jsonValue as? String).flatMap(date1Fmt.date)
    
            // 如果jsonValue是字符串,就直接转成Date
            // 由于NSDate与Date之间是可以桥接转换的,所以返回Date给NSDate属性也是没有问题的
            case "date2": return (jsonValue as? String).flatMap(date2Fmt.date)
    
            default: return jsonValue
    
            }
        }
    }
    
    let date1 = "2008-09-09"
    let date2 = "2011-11-12 14:20:30.888"
    
    let json: [String: Any] = [
        "date1": date1,
        "date2": date2
    ]
    
    let student = json.kj.model(Student.self)
    // 将DateNSDate转回字符串进行比较
    XCTAssert(student.date1.flatMap(date1Fmt.string) == date1)
    XCTAssert(student.date2.flatMap(date2Fmt.string) == date2)
    

    不确定类型

    // 有时候服务器返回的某个字段的内容类型可能是不确定的
    // 客户端可以先标记为Any类型或者AnyObject类型或者协议类型等不确定类型
    
    struct Person: Convertible {
        var name: String = ""
        var pet: Any?
    
        func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
            // 如果不是`pet`属性,就按照默认处理
            if property.name != "pet" { return jsonValue }
            // 如果是`pet`属性,并且`jsonValue`是个字典,就转换为`Dog`模型实例
            // 具体判断逻辑可以根据实际开发需求而定
            return (jsonValue as? [String: Any])?.kj.model(Dog.self)
        }
    }
    
    struct Dog: Convertible {
        var name: String = ""
        var weight: Double = 0.0
    }
    
    let json: [String: Any] = [
        "name": "Jack",
        "pet": ["name": "Wang", "weight": 109.5]
    ]
    
    let person = json.kj.model(Person.self)
    XCTAssert(person.name == "Jack")
    
    let pet = person.pet as? Dog
    XCTAssert(pet?.name == "Wang")
    XCTAssert(pet?.weight == 109.5)
    
    /*---------------------------------------------*/
    
    class Book: Convertible {
        var name: String = ""
        var price: Double = 0.0
        required init() {}
    }
    
    struct Person: Convertible {
        var name: String = ""
        // [AnyObject]、[Convertible]、NSArray、NSMutableArray
        var books: [Any]?
        
        func kj_modelValue(from jsonValue: Any?,
                           _ property: Property) -> Any? {
            if property.name != "books" { return jsonValue }
            // if books is `NSMutableArray`, neet convert `Array` to `NSMutableArray`
            // because `Array` to `NSMutableArray` is not a bridging conversion
            return (jsonValue as? [Any])?.kj.modelArray(Book.self)
        }
    }
    
    let name = "Jack"
    let books = [
        (name: "Fast C++", price: 666),
        (name: "Data Structure And Algorithm", price: 1666)
    ]
    
    let json: [String: Any] = [
        "name": name,
        "books": [
            ["name": books[0].name, "price": books[0].price],
            ["name": books[1].name, "price": books[1].price]
        ]
    ]
    
    let person = json.kj.model(Person.self)
    XCTAssert(person.name == name)
    
    XCTAssert(person.books?.count == books.count)
    
    let book0 = person.books?[0] as? Book
    XCTAssert(book0?.name == books[0].name)
    XCTAssert(book0?.price == Double(books[0].price))
    
    let book1 = person.books?[1] as? Book
    XCTAssert(book1?.name == books[1].name)
    XCTAssert(book1?.price == Double(books[1].price))
    

    其他例子

    struct Student: Convertible {
        var age: Int = 0
        var name: String = ""
    
        func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? {
            switch property.name {
    
            // 如果`age`属性的`jsonValue`是整数,就加上5
            case "age": return (jsonValue as? Int).flatMap { $0 + 5 }
    
            // 如果`name `属性的`jsonValue`是字符串,就在前面加上`kj_`
            case "name": return (jsonValue as? String).flatMap { "kj_" + $0 }
    
            default: return jsonValue
    
            }
        }
    }
    
    let json: [String: Any] = [
        "age": 10,
        "name": "Jack"
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.age == 15)
    XCTAssert(student.name == "kj_Jack")
    

    其他实现思路

    // 关于值过滤、自定义值处理的逻辑,也可以在模型转换完毕之后进行
    
    struct Student: Convertible {
        var age: Int = 0
        var name: String = ""
    
        // 实现`kj_didConvertToModel`方法,在这里修改转换之后的属性值
        mutating func kj_didConvertToModel(from json: [String: Any]) {
            age += 5
            name = "kj_" + name
        }
    }
    
    let json: [String: Any] = [
        "age": 10,
        "name": "Jack"
    ]
    
    let student = json.kj.model(Student.self)
    XCTAssert(student.age == 15)
    XCTAssert(student.name == "kj_Jack")
    

    最后的提示

    • kj_modelValue也支持ConvertibleConfig配置,用法类似于kj_modelKey,参考第三篇文章
  • 相关阅读:
    leetcode5 Longest Palindromic Substring
    leetcode17 Letter Combinations of a Phone Number
    leetcode13 Roman to Integer
    leetcode14 Longest Common Prefix
    leetcode20 Valid Parentheses
    leetcode392 Is Subsequence
    leetcode121 Best Time to Buy and Sell Stock
    leetcode198 House Robber
    leetcode746 Min Cost Climbing Stairs
    tomcat下使用druid配置jnid数据源
  • 原文地址:https://www.cnblogs.com/mjios/p/11365528.html
Copyright © 2011-2022 走看看