import Foundation
@objc protocol DictModelProtocol{
///自定义映射
///
/// :returns: 返回可选映射关系字典 [属性名: 自定义对象名称]
/// :class 替换成 static 是 swift 1.2 修改的
static func customClassMapping() -> [String: String]?
}
///字典转模型工具
class SwiftDictModel {
//单例,全局访问入口
static let sharedManger = SwiftDictModel()
/// 将字典转换成模型对象
///
/// :param: dict 数据字典
/// :param: cls 模型类
///
/// :returns: 实例化的类对象
func objectWithDictionary(dict:NSDictionary,cls:AnyClass) -> AnyObject?{
//1. 取出模型类的字典
let dictInfo = fullModelinfo(cls)
//实例化对象
var obj:AnyObject = cls.alloc()
//遍历模型字典,有什么属性就设置什么属性
// k 应该 和 dict 中的 key 是一致的
for (k,v) in dictInfo {
//取出字典中的内容
if let value: AnyObject? = dict[k]{
println("要设置数值的 \(value) + key \(k)")
//判断是否是自定义类
//json 反序列化的时候,如果是null 值,保存在字典中的事NSNull()
if v.isEmpty && !(value === NSNull()){
obj.setValue(value, forKey: k)
}else{
let type = "\(value!.classForCoder)"
println("\t自定义对象 \(value) \(k) \(v) ---- type \(type)")
//两种可能,字典/数组
if type == "NSDictionary"{
// value 是字典-> 将 value 的字典转换成 Info 的对象
if let subObj: AnyObject? = objectWithDictionary(value as! NSDictionary, cls: NSClassFromString(v)){
//使用kvc设置数值
obj.setValue(subObj, forKey: k)
}
}else if type == "NSArray" {
//value 是数组
//如果是数组如何处理? 遍历数组,继续处理数组中的字典
if let subObj:AnyObject? = objectWithArray(value as! NSArray, cls: NSClassFromString(v)){
obj.setValue(subObj, forKey: k)
}
}
}
}
}
println(dictInfo)
return obj
}
///将数组转换成模型字典
///
/// :parm: array 数组的描述
/// : param: cls 模型类
///
/// :returns: 模型数组
func objectWithArray(array: NSArray, cls: AnyClass) -> [AnyObject]? {
//创建一个数组
var result = [AnyObject]()
//1.遍历数组
//可能存在什么类型? 字典/数组
for value in array{
let type = "\(value.classForCoder)"
if type == "NSDictionary"{
if let subObj:AnyObject = objectWithDictionary(value as! NSDictionary, cls: cls){
result.append(subObj)
}
}else if type == "NSArray"{
if let subObj: AnyObject = objectWithArray(value as! NSArray, cls: cls){
result.append(subObj)
}
}
}
return result
}
/// 缓存字典 格式[类名:模型字典, 类名2:模型字典]
var modelCache = [String:[String:String]]()
/// 获取模型类的完整信息
///
///: parm:cls 模型类
func fullModelinfo(cls:AnyClass)-> [String: String] {
// 判断类信息是否已经被缓存
if let cache = modelCache["\(cls)"] {
println("\(cls)已经被缓存")
return cache
}
var currentCls: AnyClass = cls
//模型字典
var dictInfo = [String:String]()
while let parent:AnyClass = currentCls.superclass(){
//取出并且拼接 currentCls 的模型字典
dictInfo.merge(modelInfo(currentCls))
currentCls = parent
println(parent)
}
// 将模型信息写入缓存
modelCache["\(cls)"] = dictInfo
println(dictInfo)
return dictInfo
}
//获取给定类的信息
func modelInfo(cls:AnyClass) -> [String: String]{
// 判断类信息是否已经被缓存
if let cache = modelCache["\(cls)"] {
println("\(cls)已经被缓存")
return cache
}
var mapping: [String:String]?
if cls.respondsToSelector("customClassMapping"){
println("实现了协议")
//调用协议方法,获取自定义对象映射关系字典
mapping = cls.customClassMapping()
println(mapping)
}
//获取累的属性
var count: UInt32 = 0
let ivars = class_copyIvarList(cls, &count)
println("有\(count)属性")
// // 定义一个类属性的字典:[属性的名字,自定对象的名称/“”]
var dictInfo = [String: String]()
for i in 0..<count {
//检索数组下标只能,用Int
let ivar = ivars[Int(i)]
//UInt8 = char, c语言的字符串
let cname = ivar_getName(ivar)
//将c 语言字符串转换成 swift 的String
let name = String.fromCString(cname)!
//println(name)
let type = mapping?[name] ?? ""
//设置字典
dictInfo[name] = type
}
free(ivars)
// 将模型信息写入缓存
modelCache["\(cls)"] = dictInfo
return dictInfo
}
}
extension Dictionary{
mutating func merge<K, V>(dict:[K:V]){
for (k,v) in dict{
//字典的分类法, 如果要使用 updateValue 需要明确的指定类型
self.updateValue(v as! Value, forKey: k as! Key)
}
}
}