ExtendCustomModelType.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // ExtendCustomType.swift
  3. // HandyJSON
  4. //
  5. // Created by zhouzhuo on 16/07/2017.
  6. // Copyright © 2017 aliyun. All rights reserved.
  7. //
  8. import Foundation
  9. public protocol _ExtendCustomModelType: _Transformable {
  10. init()
  11. mutating func willStartMapping()
  12. mutating func mapping(mapper: HelpingMapper)
  13. mutating func didFinishMapping()
  14. }
  15. extension _ExtendCustomModelType {
  16. public mutating func willStartMapping() {}
  17. public mutating func mapping(mapper: HelpingMapper) {}
  18. public mutating func didFinishMapping() {}
  19. }
  20. fileprivate func convertKeyIfNeeded(dict: [String: Any]) -> [String: Any] {
  21. if HandyJSONConfiguration.deserializeOptions.contains(.caseInsensitive) {
  22. var newDict = [String: Any]()
  23. dict.forEach({ (kvPair) in
  24. let (key, value) = kvPair
  25. newDict[key.lowercased()] = value
  26. })
  27. return newDict
  28. }
  29. return dict
  30. }
  31. fileprivate func getRawValueFrom(dict: [String: Any], property: PropertyInfo, mapper: HelpingMapper) -> Any? {
  32. let address = Int(bitPattern: property.address)
  33. if let mappingHandler = mapper.getMappingHandler(key: address) {
  34. if let mappingPaths = mappingHandler.mappingPaths, mappingPaths.count > 0 {
  35. for mappingPath in mappingPaths {
  36. if let _value = dict.findValueBy(path: mappingPath) {
  37. return _value
  38. }
  39. }
  40. return nil
  41. }
  42. }
  43. if HandyJSONConfiguration.deserializeOptions.contains(.caseInsensitive) {
  44. return dict[property.key.lowercased()]
  45. }
  46. return dict[property.key]
  47. }
  48. fileprivate func convertValue(rawValue: Any, property: PropertyInfo, mapper: HelpingMapper) -> Any? {
  49. if rawValue is NSNull { return nil }
  50. if let mappingHandler = mapper.getMappingHandler(key: Int(bitPattern: property.address)), let transformer = mappingHandler.assignmentClosure {
  51. return transformer(rawValue)
  52. }
  53. if let transformableType = property.type as? _Transformable.Type {
  54. return transformableType.transform(from: rawValue)
  55. } else {
  56. return extensions(of: property.type).takeValue(from: rawValue)
  57. }
  58. }
  59. fileprivate func assignProperty(convertedValue: Any, instance: _ExtendCustomModelType, property: PropertyInfo) {
  60. if property.bridged {
  61. (instance as! NSObject).setValue(convertedValue, forKey: property.key)
  62. } else {
  63. extensions(of: property.type).write(convertedValue, to: property.address)
  64. }
  65. }
  66. fileprivate func readAllChildrenFrom(mirror: Mirror) -> [(String, Any)] {
  67. var children = [(label: String?, value: Any)]()
  68. let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)!
  69. children += mirrorChildrenCollection
  70. var currentMirror = mirror
  71. while let superclassChildren = currentMirror.superclassMirror?.children {
  72. let randomCollection = AnyRandomAccessCollection(superclassChildren)!
  73. children += randomCollection
  74. currentMirror = currentMirror.superclassMirror!
  75. }
  76. var result = [(String, Any)]()
  77. children.forEach { (child) in
  78. if let _label = child.label {
  79. result.append((_label, child.value))
  80. }
  81. }
  82. return result
  83. }
  84. fileprivate func merge(children: [(String, Any)], propertyInfos: [PropertyInfo]) -> [String: (Any, PropertyInfo?)] {
  85. var infoDict = [String: PropertyInfo]()
  86. propertyInfos.forEach { (info) in
  87. infoDict[info.key] = info
  88. }
  89. var result = [String: (Any, PropertyInfo?)]()
  90. children.forEach { (child) in
  91. result[child.0] = (child.1, infoDict[child.0])
  92. }
  93. return result
  94. }
  95. // this's a workaround before https://bugs.swift.org/browse/SR-5223 fixed
  96. extension NSObject {
  97. static func createInstance() -> NSObject {
  98. return self.init()
  99. }
  100. }
  101. extension _ExtendCustomModelType {
  102. static func _transform(from object: Any) -> Self? {
  103. if let dict = object as? [String: Any] {
  104. // nested object, transform recursively
  105. return self._transform(dict: dict) as? Self
  106. }
  107. return nil
  108. }
  109. static func _transform(dict: [String: Any]) -> _ExtendCustomModelType? {
  110. var instance: Self
  111. if let _nsType = Self.self as? NSObject.Type {
  112. instance = _nsType.createInstance() as! Self
  113. } else {
  114. instance = Self.init()
  115. }
  116. instance.willStartMapping()
  117. _transform(dict: dict, to: &instance)
  118. instance.didFinishMapping()
  119. return instance
  120. }
  121. static func _transform(dict: [String: Any], to instance: inout Self) {
  122. guard let properties = getProperties(forType: Self.self) else {
  123. InternalLogger.logDebug("Failed when try to get properties from type: \(type(of: Self.self))")
  124. return
  125. }
  126. // do user-specified mapping first
  127. let mapper = HelpingMapper()
  128. instance.mapping(mapper: mapper)
  129. // get head addr
  130. let rawPointer = instance.headPointer()
  131. InternalLogger.logVerbose("instance start at: ", Int(bitPattern: rawPointer))
  132. // process dictionary
  133. let _dict = convertKeyIfNeeded(dict: dict)
  134. let instanceIsNsObject = instance.isNSObjectType()
  135. let bridgedPropertyList = instance.getBridgedPropertyList()
  136. for property in properties {
  137. let isBridgedProperty = instanceIsNsObject && bridgedPropertyList.contains(property.key)
  138. let propAddr = rawPointer.advanced(by: property.offset)
  139. InternalLogger.logVerbose(property.key, "address at: ", Int(bitPattern: propAddr))
  140. if mapper.propertyExcluded(key: Int(bitPattern: propAddr)) {
  141. InternalLogger.logDebug("Exclude property: \(property.key)")
  142. continue
  143. }
  144. let propertyDetail = PropertyInfo(key: property.key, type: property.type, address: propAddr, bridged: isBridgedProperty)
  145. InternalLogger.logVerbose("field: ", property.key, " offset: ", property.offset, " isBridgeProperty: ", isBridgedProperty)
  146. if let rawValue = getRawValueFrom(dict: _dict, property: propertyDetail, mapper: mapper) {
  147. if let convertedValue = convertValue(rawValue: rawValue, property: propertyDetail, mapper: mapper) {
  148. assignProperty(convertedValue: convertedValue, instance: instance, property: propertyDetail)
  149. continue
  150. }
  151. }
  152. InternalLogger.logDebug("Property: \(property.key) hasn't been written in")
  153. }
  154. }
  155. }
  156. extension _ExtendCustomModelType {
  157. func _plainValue() -> Any? {
  158. return Self._serializeAny(object: self)
  159. }
  160. static func _serializeAny(object: _Transformable) -> Any? {
  161. let mirror = Mirror(reflecting: object)
  162. guard let displayStyle = mirror.displayStyle else {
  163. return object.plainValue()
  164. }
  165. // after filtered by protocols above, now we expect the type is pure struct/class
  166. switch displayStyle {
  167. case .class, .struct:
  168. let mapper = HelpingMapper()
  169. // do user-specified mapping first
  170. if !(object is _ExtendCustomModelType) {
  171. InternalLogger.logDebug("This model of type: \(type(of: object)) is not mappable but is class/struct type")
  172. return object
  173. }
  174. let children = readAllChildrenFrom(mirror: mirror)
  175. guard let properties = getProperties(forType: type(of: object)) else {
  176. InternalLogger.logError("Can not get properties info for type: \(type(of: object))")
  177. return nil
  178. }
  179. var mutableObject = object as! _ExtendCustomModelType
  180. let instanceIsNsObject = mutableObject.isNSObjectType()
  181. let head = mutableObject.headPointer()
  182. let bridgedProperty = mutableObject.getBridgedPropertyList()
  183. let propertyInfos = properties.map({ (desc) -> PropertyInfo in
  184. return PropertyInfo(key: desc.key, type: desc.type, address: head.advanced(by: desc.offset),
  185. bridged: instanceIsNsObject && bridgedProperty.contains(desc.key))
  186. })
  187. mutableObject.mapping(mapper: mapper)
  188. let requiredInfo = merge(children: children, propertyInfos: propertyInfos)
  189. return _serializeModelObject(instance: mutableObject, properties: requiredInfo, mapper: mapper) as Any
  190. default:
  191. return object.plainValue()
  192. }
  193. }
  194. static func _serializeModelObject(instance: _ExtendCustomModelType, properties: [String: (Any, PropertyInfo?)], mapper: HelpingMapper) -> [String: Any] {
  195. var dict = [String: Any]()
  196. for (key, property) in properties {
  197. var realKey = key
  198. var realValue = property.0
  199. if let info = property.1 {
  200. if info.bridged, let _value = (instance as! NSObject).value(forKey: key) {
  201. realValue = _value
  202. }
  203. if mapper.propertyExcluded(key: Int(bitPattern: info.address)) {
  204. continue
  205. }
  206. if let mappingHandler = mapper.getMappingHandler(key: Int(bitPattern: info.address)) {
  207. // if specific key is set, replace the label
  208. if let mappingPaths = mappingHandler.mappingPaths, mappingPaths.count > 0 {
  209. // take the first path, last segment if more than one
  210. realKey = mappingPaths[0].segments.last!
  211. }
  212. if let transformer = mappingHandler.takeValueClosure {
  213. if let _transformedValue = transformer(realValue) {
  214. dict[realKey] = _transformedValue
  215. }
  216. continue
  217. }
  218. }
  219. }
  220. if let typedValue = realValue as? _Transformable {
  221. if let result = self._serializeAny(object: typedValue) {
  222. dict[realKey] = result
  223. continue
  224. }
  225. }
  226. InternalLogger.logDebug("The value for key: \(key) is not transformable type")
  227. }
  228. return dict
  229. }
  230. }