运行时:
1 会用来开发oc的
2如果在程序开发中,有一些动态的需求,通常可以使用运行时来处理关于运行时。
总共有三种常见的使用技术
1>交换方法
2>动态获取类的信息
3>在分类中,动态关联属性
思路
1.获取字典
2.根据字典的内容创建并且填充模型
3.需要动态的知道模型类都包含那些属性
class_copyProptiesList
class_copyIVarsList
4.测试子类的模型信息
运行时class_copyIvarList
不会获取父类的属性列表
5.模型必须继承自NSObject
,因为 只有继承自这个才能使用KVC
赋值,还有就是方便遍历
6.拼接字典
7.需要考虑到性能优化的问题 -》 一旦类的模型信息获取到了,就不需要再次获取
这里要使用这个@objc ,Runtime
才能检测到;子类属性的非基本类型的映射;例如你模型中的属性是你自定义的类的时候需要实现这个协议方法。
@objc public protocol DictModelProtocol {
/// 自定义类的映射
static func customClassMapping() -> [String: String]?
}
这里对字典类型进行扩展,实现字典的合并。
extension Dictionary {
/// 将字典合并到当前字典
mutating func merge<K, V>(dict: [K: V]) {
for (k, v) in dict {
self.updateValue(v as! Value, forKey: k as! Key)
}
}
}
以下就是整个字典模型之间的转换代码:
字典转模型时,基本数据类型 利用
KVC
进行赋值,自定义类型 需要另外处理
/// 字典转模型管理器
public class DictModelManager {
private static let instance = DictModelManager()
/// 全局统一访问入口
public class var sharedManager: DictModelManager {
return instance
}
/// 字典转模型
/// - parameter dict: 数据字典
/// - parameter cls: 模型类
///
/// - returns: 模型对象
public func objectWithDictionary(dict: NSDictionary, cls: AnyClass) -> AnyObject? {
/// swift 中类的完整名称是 命名空间 + 类名 后边进行类名传递的时候需要拼接上 命名空间
// 动态获取命名空间
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
// 模型信息
let infoDict = fullModelInfo(cls)
let obj: AnyObject = (cls as! NSObject.Type).init()
autoreleasepool {
// 3. 遍历模型字典
for (k, v) in infoDict {
if let value: AnyObject = dict[k] {
if v.isEmpty {
if !(value === NSNull()) {
obj.setValue(value, forKey: k)
}
} else {
let type = "\(value.classForCoder)"
if type == "NSDictionary" {
if let subObj: AnyObject = objectWithDictionary(value as! NSDictionary, cls: NSClassFromString(ns + "." + v)!) {
obj.setValue(subObj, forKey: k)
}
} else if type == "NSArray" {
if let subObj: AnyObject = objectsWithArray(value as! NSArray, cls: NSClassFromString(ns + "." + v)!) {
obj.setValue(subObj, forKey: k)
}
}
}
}
}
}
return obj
}
/// 创建自定义对象数组
///
/// - parameter NSArray: 字典数组
/// - parameter cls: 模型类
///
/// - returns: 模型数组
public func objectsWithArray(array: NSArray, cls: AnyClass) -> NSArray? {
var list = [AnyObject]()
autoreleasepool { () -> () in
for value in array {
let type = "\(value.classForCoder)"
if type == "NSDictionary" {
if let subObj: AnyObject = objectWithDictionary(value as! NSDictionary, cls: cls) {
list.append(subObj)
}
} else if type == "NSArray" {
if let subObj: AnyObject = objectsWithArray(value as! NSArray, cls: cls) {
list.append(subObj)
}
}
}
}
if list.count > 0 {
return list
} else {
return nil
}
}
/// 模型转字典
///
/// - parameter obj: 模型对象
///
/// - returns: 字典信息
public func objectDictionary(obj: AnyObject) -> [String: AnyObject]? {
// 1. 取出对象模型字典
let infoDict = fullModelInfo(obj.classForCoder)
var result = [String: AnyObject]()
// 2. 遍历字典
for (k, v) in infoDict {
var value: AnyObject? = obj.valueForKey(k)
if value == nil {
value = NSNull()
}
if v.isEmpty || value === NSNull() {
result[k] = value
} else {
let type = "\(value!.classForCoder)"
var subValue: AnyObject?
if type == "NSArray" {
subValue = objectArray(value! as! [AnyObject])
} else {
subValue = objectDictionary(value!)
}
if subValue == nil {
subValue = NSNull()
}
result[k] = subValue
}
}
if result.count > 0 {
return result
} else {
return nil
}
}
/// 模型数组转字典数组
///
/// - parameter array: 模型数组
///
/// - returns: 字典数组
public func objectArray(array: [AnyObject]) -> [AnyObject]? {
var result = [AnyObject]()
for value in array {
let type = "\(value.classForCoder)"
var subValue: AnyObject?
if type == "NSArray" {
subValue = objectArray(value as! [AnyObject])
} else {
subValue = objectDictionary(value)
}
if subValue != nil {
result.append(subValue!)
}
}
if result.count > 0 {
return result
} else {
return nil
}
}
// MARK: - 私有函数
/// 加载完整类信息 取出本身的属性 和 所有父类都有的属性 ,进行拼接到一个字典然后返回
///
/// - parameter cls: 模型类
///
/// - returns: 模型类完整信息
func fullModelInfo(cls: AnyClass) -> [String: String] {
// 检测缓冲池
if let cache = modelCache["\(cls)"] {
return cache
}
var currentCls: AnyClass = cls
var infoDict = [String: String]()
while let parent: AnyClass = currentCls.superclass() {
infoDict.merge(modelInfo(currentCls))
currentCls = parent
}
// 写入缓冲池
modelCache["\(cls)"] = infoDict
return infoDict
}
/// 加载类信息
///加载单一的类信息,并且存入缓存池
/// - parameter cls: 模型类
///
/// - returns: 模型类信息
func modelInfo(cls: AnyClass) -> [String: String] {
// 检测缓冲池
if let cache = modelCache["\(cls)"] {
return cache
}
// 拷贝属性列表
var count: UInt32 = 0
let properties = class_copyPropertyList(cls, &count)
// 检查类是否实现了协议
var mappingDict: [String: String]?
if cls.respondsToSelector("customClassMapping") {
mappingDict = cls.customClassMapping()
}
var infoDict = [String: String]()
for i in 0..<count {
let property = properties[Int(i)]
// 属性名称
let cname = property_getName(property)
let name = String.fromCString(cname)!
let type = mappingDict?[name] ?? ""
infoDict[name] = type
}
free(properties)
// 写入缓冲池
modelCache["\(cls)"] = infoDict
return infoDict
}
/// 模型缓冲,[类名: 模型信息字典]
var modelCache = [String: [String: String]]()
}