Нет описания

NSObject+Motis.h 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //
  2. // NSObject+Motis.h
  3. // Copyright 2014 Mobile Jazz
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #import <Foundation/Foundation.h>
  17. /* *************************************************************************************************************************************** *
  18. * MACROS
  19. * *************************************************************************************************************************************** */
  20. /**
  21. * Use the mts_key(name) macro to create strings for property names.
  22. **/
  23. #define mts_key(name) NSStringFromSelector(@selector(name))
  24. /* *************************************************************************************************************************************** *
  25. * Motis Methods
  26. * *************************************************************************************************************************************** */
  27. #pragma mark - Motis
  28. /**
  29. * Extends NSObject adding parsing capabilities from JSON dictionaries.
  30. * To parse and set the object from the JSON dictionary, use the methods `mts_setValue:forKey:` or `mts_setValuesForKeysWithDictionary:`.
  31. **/
  32. @interface NSObject (Motis)
  33. /** ---------------------------------------------- **
  34. * @name Object Mapping Methods
  35. ** ---------------------------------------------- **/
  36. /**
  37. * Parse and set the value for the given key. This method validates the value.
  38. * @param value The value to parse and set.
  39. * @param key The key of the attribute to set the value.
  40. * @discussion This method will check if the key is mappable using the dictionary specified in `mts_motisMapping`. Once the key mapped, this method will call the KVC method `setValue:forKey` to set the value. If value is nil or [NSNull null], the method will invoke instead `setNilValueForKey:`. If value is an array, `mts_parseArrayValue:forKey:parseKey:` will be invoked for each object.
  41. **/
  42. - (void)mts_setValue:(id)value forKey:(NSString *)key;
  43. /**
  44. * Parse and set the key-values of the dictionary. This method will fire validation for each value.
  45. * @param dictionary The dictionary to parse and set.
  46. * @discussion This method will call for each dictionary pair key-value the method `mts_setValue:forKey:`.
  47. **/
  48. - (void)mts_setValuesForKeysWithDictionary:(NSDictionary *)dictionary;
  49. /** ---------------------------------------------- **
  50. * @name Key-Mapping Getters
  51. ** ---------------------------------------------- **/
  52. /**
  53. * Retrieve an object value for a given key. The key is mapped via the motis mapping.
  54. * @param key The key (will be mapped)
  55. * @return The corresponding value for the given key if available, otherwise nil.
  56. **/
  57. - (id)mts_valueForKey:(NSString*)key;
  58. /**
  59. * Returns a dictionary containing the given keys and the corresponding values.
  60. * @param keys An array with keys.
  61. * @return The dictionary with key-values.
  62. * @discussion This method uses the motis mapping to retrieve the values for the given keys. The keys used in the returned dictionary are the ones specified in the given array. WARNING: this method may not return a JSON serializable dictionary, just returns the object values.
  63. **/
  64. - (NSDictionary*)mts_dictionaryWithValuesForKeys:(NSArray *)keys;
  65. /** ---------------------------------------------- **
  66. * @name Logging objects
  67. ** ---------------------------------------------- **/
  68. /**
  69. * Returns the extended object description.
  70. * @return The custom extended object description.
  71. **/
  72. - (NSString*)mts_extendedObjectDescription;
  73. @end
  74. /*
  75. * MOTIS AUTOMATIC VALIDATION
  76. *
  77. * Motis object mapping adds automatic validation for your properties. This means the system will try to convert into your property type the input value.
  78. * The following table indicates the supported validations in the current version:
  79. *
  80. +------------+---------------------+------------------------------------------------------------------------------------+
  81. | JSON Type | Property Type | Comments |
  82. +------------+---------------------+------------------------------------------------------------------------------------+
  83. | string | NSString | No validation is requried |
  84. | number | NSNumber | No validation is requried |
  85. | number | basic type (1) | No validation is requried |
  86. | array | NSArray | No validation is requried |
  87. | dictionary | NSDictionary | No validation is requried |
  88. | - | - | - |
  89. | string | bool | string parsed with method -boolValue and by comparing with "true" and "false" |
  90. | string | unsigned long long | string parsed with NSNumberFormatter (allowFloats disabled) |
  91. | string | basic types (2) | value generated automatically by KVC (NSString's '-intValue', '-longValue', etc) |
  92. | string | NSNumber | string parsed with method -doubleValue |
  93. | string | NSURL | created using [NSURL URLWithString:] |
  94. | string | NSData | attempt to decode base64 encoded string |
  95. | string | NSDate | default date format "2011-08-23 10:52:00". Check '+mts_validationDateFormatter.' |
  96. | - | - | - |
  97. | number | NSDate | timestamp since 1970 |
  98. | number | NSString | string by calling NSNumber's '-stringValue' |
  99. | - | - | - |
  100. | array | NSMutableArray | creating new instance from original array |
  101. | array | NSSet | creating new instance from original array |
  102. | array | NSMutableSet | creating new instance from original array |
  103. | array | NSOrderedSet | creating new instance from original array |
  104. | array | NSMutableOrderedSet | creating new instance from original array |
  105. | - | - | - |
  106. | dictionary | NSMutableDictionary | creating new instance from original dictionary |
  107. | dictionary | custom NSObject | Motis recursive call. Check '-mts_willCreateObject..' and '-mtd_didCreateObject:' |
  108. | - | - | - |
  109. | null | nil | if property is type object |
  110. | null | <UNDEFINED> | if property is basic type (3). Check KVC method '-setNilValueForKey:' |
  111. +------------+---------------------+------------------------------------------------------------------------------------+
  112. *
  113. * basic type (1) : int, unsigned int, long, unsigned long, long long, unsigned long long, float, double)
  114. * basic type (2) : int, unsigned int, long, unsigned long, float, double)
  115. * basic type (3) : any basic type (non-object type).
  116. *
  117. */
  118. /* *************************************************************************************************************************************** *
  119. * Motis Subclassing
  120. * *************************************************************************************************************************************** */
  121. #pragma mark - Motis_Subclassing
  122. /**
  123. * Motis Object Subclassing
  124. *
  125. * OBJECT MAPPINGS
  126. *
  127. * In order to use Motis you must define mappings between JSON keys and object properties by overriding the following methods:
  128. *
  129. * - `+mts_mapping`: Subclasses must override this method and return the mapping between the JSON keys and the object properties. The mapping may contain KeyPath to JSON values.
  130. * - `+mts_shouldSetUndefinedKeys`: Optionally, subclasses can override this method to forbid Motis from automatically setting keys not found in the mapping. The default is `YES`.
  131. *
  132. * VALIDATION METHODS
  133. *
  134. * To support automatic validation you must override:
  135. *
  136. * - `+mts_arrayClassMapping`: If your objects has properties of type `NSArray`, override this method and define a mapping between the array property name and the expected content object class.
  137. *
  138. * However, you can validate manually any value before the automatic validation is done. If you implements manually validation for a property, the system won't perform the automatic validation.
  139. * To implement manual validation you must override:
  140. *
  141. * - `-validate<Key>:error:` For each property to manually validate implement this method with <Key> being the name of the object property. This is a KVC validation method.
  142. * - `-mts_validateArrayObject:forArrayKey:`: For those property of type array, implement this method to validate their content.
  143. *
  144. * OTHER METHODS TO SUBCLASS
  145. *
  146. * - `-setValue:forUndefinedKey:`: KVC Method to handle undefined keys. By default this method throws an exception. This method is called when a setting a value for an unknown key.
  147. * - `-setNilValueForKey:`: KVC Method to nullify a basic type property. By default this method throws an exception. This method is called when a json field with value "null" is received.
  148. * - `-mts_ignoredSetValue:forUndefinedMappingKey`: If undefined keys are disabled (`mts_motisShouldSetUndefinedKeys`), this method will be called when a undefined mapping key is found.
  149. * - `-mts_invalidValue:forKey:error:`: If value is does not pass valiation, this method is called after aborting the value setting.
  150. * - `-mts_invalidValue:forArrayKey:error:`: if an array item does not pass validation, this method is called after aborting the item setting.
  151. **/
  152. @interface NSObject (Motis_Subclassing)
  153. /** ---------------------------------------------- **
  154. * @name Object Mappings
  155. ** ---------------------------------------------- **/
  156. /**
  157. * Returns the mapping to be used in the object mapping stage. The default value is an empty dictionary.
  158. * @return the mapping in a dictionary.
  159. * @discussion Subclasses must override this method and specify a custom mapping dictionary for their class level. When needed, motis will collect all mapping dictionaries from each subclass level in the class hierarchy and create the overall mapping. The returned mapping will be cached.
  160. **/
  161. + (NSDictionary*)mts_mapping;
  162. /**
  163. * Returns whether Motis should set keys not found in the mapping. Default value is `NO`. However, if no mapping is defined this method is ignored and Motis will attempt to set values for any key.
  164. * @return `YES` if Motis should set undefined mapping keys, `NO` if only the keys defined `+mts_mapping` can be set.
  165. * @discussion Subclasses may override to return `YES`. Remember that when setting values for undefined keys KVC will rise an exception which you can remove by overriding the KVC method `-setValue:forUndefinedKey:.
  166. **/
  167. + (BOOL)mts_shouldSetUndefinedKeys;
  168. /** ---------------------------------------------- **
  169. * @name Automatic Validation
  170. ** ---------------------------------------------- **/
  171. /**
  172. * Return a mapping between the array property name to the contained object class type.
  173. * For example: @{@"myArrayPropertyName": User.class, ... };
  174. * @return A dictionary with the array content mapping. When needed, motis will collect all mapping dictionaries from each subclass level in the class hierarchy and create the overall mapping.
  175. **/
  176. + (NSDictionary*)mts_arrayClassMapping;
  177. /**
  178. * While validating automatically your JSON objects, Motis object mapping might create new objects. This method is called just before new objects are created.
  179. * @param typeClass The object class. A new object of this class is going to be created.
  180. * @param dictionary The JSON-based dictionary which will be parsed into the new object.
  181. * @param key The property name of the object to assign or the array name where the object will belong to.
  182. * @param abort A flag boolean. Return YES if you want to abort (because of dictionary incoherences, for example). When aborting the object is not setted or included inside an array.
  183. * @return A custom object or nil.
  184. * @discussion If you return nil, Motis object mapping will create automatically the new instance of class typeClass and parse the dictionary into it. Optionally, you can create the object and parse the dictionary manually. You must return the custom object as a return value of this method.
  185. **/
  186. - (id)mts_willCreateObjectOfClass:(Class)typeClass withDictionary:(NSDictionary*)dictionary forKey:(NSString*)key abort:(BOOL*)abort;
  187. /**
  188. * The newer created object for the given key.
  189. * @param object The new object.
  190. * @param key The property name of the object or the array name where the object belongs to.
  191. **/
  192. - (void)mts_didCreateObject:(id)object forKey:(NSString *)key;
  193. /**
  194. * Returns a date formatter for automatic validation from string to date (default is nil).
  195. * @return The date formatter.
  196. * @discussion The default date formatter format is nil, meaning that strings will be validated into dates only if they represent a timestamp. Subclasses can override this method and provide a custom date formatter. If different keys have different date formats, you must validate manually the property.
  197. **/
  198. + (NSDateFormatter*)mts_validationDateFormatter;
  199. /** ---------------------------------------------- **
  200. * @name Manual Validation
  201. ** ---------------------------------------------- **/
  202. /**
  203. * Method called by `-mts_setValue:forKey:` to validate manually each value. The default implementation fires KVC validation.
  204. * @param ioValue The value to be validated. You can replace the value by assigning a new object to the pointer.
  205. * @param inKey The key of the value.
  206. * @param error The validation error.
  207. * @return YES if value is accepted, otherwise NO.
  208. * @discussion Subclasses may override in order to not perform KVC validation. For example, when using CoreData you must override this method and not do KVC validation (as KVC validation is implemented by NSManagedObject and used by NSManagedObjectContext).
  209. **/
  210. - (BOOL)mts_validateValue:(inout __autoreleasing id *)ioValue forKey:(NSString *)inKey error:(out NSError *__autoreleasing *)outError;
  211. /**
  212. * Subclasses may override to validate array values. The default implementation accepts (return YES) the default value.
  213. * @param ioValue The value to be validated. You can replace the value by assigning a new object to the pointer.
  214. * @param arrayKey The name of the key in which the containing array will be assigned.
  215. * @return YES if value is accepted, NO to avoid adding this value inside the array.
  216. **/
  217. - (BOOL)mts_validateArrayObject:(inout __autoreleasing id *)ioValue forArrayKey:(NSString *)arrayKey error:(out NSError *__autoreleasing *)outError;
  218. /** ---------------------------------------------- **
  219. * @name Other methods
  220. ** ---------------------------------------------- **/
  221. /**
  222. * Notifies ignored values for undefined mapping keys.
  223. * @param value The value that has not been setted.
  224. * @param key The key undefined in the mapping.
  225. * @discussion This method is called when the method `-mts_motisShouldSetUndefinedKeys` return NO and Motis is trying to set a value for an undefined mapping key.
  226. **/
  227. - (void)mts_ignoredSetValue:(id)value forUndefinedMappingKey:(NSString*)key;
  228. /**
  229. * If a value does not pass validation, this method is called after aborting the value setting.
  230. * @param value The invalid value.
  231. * @param key The key for the value.
  232. * @param error The validation error.
  233. **/
  234. - (void)mts_invalidValue:(id)value forKey:(NSString *)key error:(NSError*)error;
  235. /**
  236. * If a array item does not pass validation, this method is called after aborting the item setting.
  237. * @param value The invalid array item.
  238. * @param key The key of the array.
  239. * @param error The validation error.
  240. **/
  241. - (void)mts_invalidValue:(id)value forArrayKey:(NSString *)key error:(NSError*)error;
  242. @end