wickwirew / Runtime

A Swift Runtime library for viewing type info, and the dynamic getting and setting of properties.
MIT License
1.08k stars 94 forks source link

set an floating number to Float sometime fail. #85

Closed coder-free closed 3 years ago

coder-free commented 3 years ago
import Runtime

class A {
    var value1: Float?
    var value2: Double?
}

func test() {
    let json = "{\"beans\":[{\"value1\":1.2,\"value2\":1.3},{\"value1\":2.2,\"value2\":2.3}]}"
    if let data = json.data(using: .utf8) {
        if let obj = try? JSONSerialization.jsonObject(with: data) {
            let dictionary: Dictionary<String, Any> = obj as! Dictionary<String, Any>
            if let beans = dictionary["beans"] as? Array<Dictionary<String, Any>> {
                for beanDic in beans {
                    print("=========================================")
                    var bean = A()
                    if let info = try? typeInfo(of: type(of: bean)) {
                        let properties = info.properties()
                        for (key, value) in beanDic {
                            if properties.contains(key) {
                                if let property = try? info.property(named: key) {
                                    print("set \(value)[type:\(type(of: value))] -> \(key)[type:\(property.type)]")
                                    try? property.set(value: value, on: &bean)
                                }
                            }
                        }
                    }
                    print("-----------------------------------------")
                    print("\(type(of: bean.value1)):\(String(describing: bean.value1)), \(type(of: bean.value2)):\(String(describing: bean.value2))")
                    print("=========================================")
                }
            }
        }
    }
}

extension TypeInfo {
    func properties() -> [String] {
        var properties: [String] = []
        for property in self.properties {
            properties.append(property.name)
        }
        return properties
    }
}

test()

got log:

=========================================
set 1.2[type:__NSCFNumber] -> value1[type:Optional<Float>]
set 1.3[type:__NSCFNumber] -> value2[type:Optional<Double>]
-----------------------------------------
Optional<Float>:nil, Optional<Double>:Optional(1.3)
=========================================
=========================================
set 2.2[type:__NSCFNumber] -> value1[type:Optional<Float>]
set 2.3[type:__NSCFNumber] -> value2[type:Optional<Double>]
-----------------------------------------
Optional<Float>:nil, Optional<Double>:Optional(2.3)
=========================================

Set Floating value to Double success. Set Floating value to Float fail.

wickwirew commented 3 years ago

Its because the values actual type from JSONSerialization.jsonObject is a Double, not a Float. Runtime will not auto convert any type for. You would need to convert it manually before setting it:

if let property = try? info.property(named: key) {
    if value is Double {
        try? property.set(value: Float(value), on: &bean)
    } else {
        try? property.set(value: value, on: &bean)
    }
}
coder-free commented 3 years ago

@wickwirew ok, thank you