JSON-to-Model internal resolution, json-to-model resolution

Source: Internet
Author: User

JSON-to-Model internal resolution, json-to-model resolution

I. Ideas: 1. Obtain all attributes and their types through the model type. 2. process the obtained json. Type processing 3. Consider the inconsistency between the dictionary key value and the model attribute name 4. Add code for archiving 5. Supplement interfaces such as JSON to dictionary, dictionary to JSON, dictionary to model 6, cache processed properties. 2. Design Mode: design Pattern Selection --------- inheritance, interface, abstract base class selection. Choose between ease of use, high efficiency, and low coupling. 3. Details and implementations first break down the tasks, implement the details of each part, and then combine them. Of course, we need to think about the design patterns used for assembly. Let's take a look at the implementation details of each part. 1. Obtain all attributes and their types through model types,
Unsigned int outCount = 0; // obtain all attributes of Class c. Here c is [Model class] objc_property_t * properties = class_copyPropertyList (c, & outCount); for (int I = 0; I <outCount; I ++) {objc_property_t propert = properties [I]; // obtain the attribute name NSString * key = @ (property_getName (propert); // obtain the attribute type, information such as CGFloat, nonatomic, and copy NSString * type = @ (property_getAttributes (propert); NSLog (@ "key = % @, type = % @", key, type );}

The Model is as follows:

// Attribute} typedef void (^ block) (); @ interface Model: NSObject @ property (nonatomic, copy) NSString * q_NSString; @ property (nonatomic, assign) CGFloat q_CGFloat; @ property (nonatomic, assign) CGRect q_CGRect; @ property (nonatomic, assign) double q_double; @ property (nonatomic, assign) int q_int; @ property (nonatomic, assign) BOOL q_bool; @ property (nonatomic, assign) float q_float; @ property (nonatomic, assign) short q_short; @ property (nonatomic, assign) long q_long; @ property (nonatomic, assign) long q_longlong; @ property (nonatomic, assign) Point q_point; @ property (nonatomic, strong) id q_id; @ property (nonatomic, weak) id <NSObject> q_delegate; @ property (nonatomic, copy) block q_block; @ property (nonatomic, strong) Model1 * q_model1; @ property SEL q_SEL; @ property Class q_Class; @ property Ivar q_Ivar; @ property Method q_Method;

The output result is

key = q_NSString , type = T@"NSString",C,N,V_q_NSStringkey = q_CGFloat , type = Td,N,V_q_CGFloatkey = q_CGRect , type = T{CGRect={CGPoint=dd}{CGSize=dd}},N,V_q_CGRectkey = q_double , type = Td,N,V_q_doublekey = q_int , type = Ti,N,V_q_intkey = q_bool , type = TB,N,V_q_boolkey = q_float , type = Tf,N,V_q_floatkey = q_short , type = Ts,N,V_q_shortkey = q_long , type = Tq,N,V_q_longkey = q_longlong , type = Tq,N,V_q_longlongkey = q_point , type = T{Point=ss},N,V_q_pointkey = q_id , type = T@,&,N,V_q_idkey = q_delegate , type = T@"<NSObject>",W,N,V_q_delegatekey = q_block , type = T@?,C,N,V_q_blockkey = q_model1 , type = T@"Model1",&,N,V_q_model1key = q_SEL , type = T:,V_q_SELkey = q_Class , type = T#,&,V_q_Classkey = q_Ivar , type = T^{objc_ivar=},V_q_Ivarkey = q_Method , type = T^{objc_method=},V_q_Method

 

Separate type with ",". The declaration of T @ "NSNumber", N, R, and Vname in the class is let name: NSNumber = NSNumber ()
  • T @ "NSNumber" indicates the type
  • N thread security is equivalent to nonmatic in Objective-C.
  • R is immutable. R is equivalent to readonly in Objective-C, and C is equivalent to copy.
  • Remove Vname from V. name is the variable name.
You can obtain the type of the attribute by processing the type. To proceed to the next step. Note: class_copyPropertyList only returns the attributes of the object class. class_copyIvarList returns all attributes and variables of the class, such as let a: Int? Is returned through class_copyPropertyList. 2. the method for processing type may be different, but the purpose is the same, that is, to distinguish different types from the type string, mainly divided into the following types: object, protocol, block, basic type, struct, custom type, Class, Ivar, Method, SEL, MJExtension are distinguished in this way, defined in MJExtensionConst
NSString *const MJPropertyTypeInt = @"i";NSString *const MJPropertyTypeShort = @"s";NSString *const MJPropertyTypeFloat = @"f";NSString *const MJPropertyTypeDouble = @"d";NSString *const MJPropertyTypeLong = @"l";NSString *const MJPropertyTypeLongLong = @"q";NSString *const MJPropertyTypeChar = @"c";NSString *const MJPropertyTypeBOOL1 = @"c";NSString *const MJPropertyTypeBOOL2 = @"b";NSString *const MJPropertyTypePointer = @"*";NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";NSString *const MJPropertyTypeMethod = @"^{objc_method=}";NSString *const MJPropertyTypeBlock = @"@?";NSString *const MJPropertyTypeClass = @"#";NSString *const MJPropertyTypeSEL = @":";NSString *const MJPropertyTypeId = @"@";
MJExtension uses string processing on type to distinguish specific types. NSScannerType. In comparison, I think it is clearer to use a class such as MJExtensionConst to store differentiated values. It is relatively good for those who read the source code. Of course, it can also be combined to use 3. Type processing for the obtained JSON.

  • It is NSNumer in JSON, and propertytype is NSString, which is common. When propertytype is NSString and NSNumber is in JSON, NSNumber is converted to NSString.
  • No value assignment is required for Readonly.
  • Nil Processing
  • Variable and immutable Processing
  • The model requires recursive processing.
  • NSString-> NSURL
  • Convert string to BOOL
  • There are also some other processes, and not every third party handles the above processes.
Part of MJEextension code
If ([value isKindOfClass: [NSStringclass]) {if (propertyClass = [NSURL class]) {// NSString-> NSURL // string transcoding value = [value mj_url];} else if (type. isNumberType) {NSString * oldValue = value; // NSString-> NSNumber value = [numberFormatter _ numberFromString: oldValue]; // if it is BOOL if (type. isBoolType) {// string to BOOL (the character string does not have the charValue method) // The system will call the charValue of the string to the BOOL type NSString * lower = [oldValue lowercaseString]; if ([lower isw.tostring: @ "yes"] | [lower iswer tostring: @ "true"]) {value = @ YES;} else if ([lower iswer tostring: @ "no"] | [lower iswer tostring: @ "false"]) {value = @ NO ;}}}}

 

4. use KVC to assign setValue: forKey: Not much. 5. consider the situations where the dictionary key value and model attribute name are inconsistent, such as id and descripition cannot be used as the attribute name. When the server is used, we need to construct another name; in addition, servers generally use the user_name naming method, while OC generally uses the hump naming method, that is, userName, so we need to establish a one-to-one correspondence. There are three methods to handle this problem:
  • Uses inheritance to define the model base class, and child classes to override the parent class method.
  • Block sets block callback.
  • Abstract base classes can be used.
We need to consider this part, because it involves how we provide interfaces and how users use them. Consider whether it is convenient to use, high efficiency, low coupling or not. First, the adoption of the inheritance method will undoubtedly result in high coupling. Of course, it is more convenient to use in most cases when the design is reasonable. The second method uses block. It solves the high coupling cost caused by inheritance. It is easy to use. This method is used for MJEextension. However, this method often allows us to call block when calling the conversion method, and convert a large string of different key values. I personally think it is better to write the conversion of different key values in the model. In encapsulation, the user is consciously guided to do so. The third method uses the abstract base class to define a protocol, the protocol provides one or more key value conversion methods. When the model complies with and implements this protocol, it finds a solution for processing. This method avoids the cost of high coupling inherited, and the user complies with the Protocol in the model to implement this method. The key-value conversion method is written in the model to avoid conversion of many things. Sometimes it needs to be written several times. Of course, this also has some disadvantages, that is, every time there is a need to convert (and the key value is very common) need to be introduced, and then follow the protocol. When several models are created consecutively, copying is not convenient. 6. For other aspects (not tested), KVC cannot be used for SEL, Method, and Ivar. If you consider these cases, you need to make a judgment. Set attributes that can be ignored when assigning values. 7. Add code to archive adding methods.
- (id)initWithCoder:(NSCoder *)decoder- (void)encodeWithCoder:(NSCoder *)encoder
Generally, we add a category to NSObject, because we can get all the attributes and corresponding values of the class. In the two methods, the attributes are traversed for encoding and decoding. To facilitate some caching, many page caches can do this. Easy to use. 8. Supplement JSON to Dictionary
+ (NSDictionary *) dictionaryWithJsonString :( NSString *) jsonString {if (jsonString = nil) {return nil;} NSData * jsonData = [jsonString dataUsingEncoding: Unknown]; NSError * error; NSDictionary * dic = [NSJSONSerialization JSONObjectWithData: jsonData options: NSJSONReadingMutableContainers error: & error]; if (error) {NSLog (@ "json parsing failed: % @", error ); return nil;} return dic ;}
This method is slightly transformed and can also output arrays, mainly in json format. 9. Convert the dictionary to JSON
+ (NSString*)dictionaryToJson:(NSDictionary *)dic{    NSError *error = nil;    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic 
                                 options:NSJSONWritingPrettyPrinted
                                 error:&error]; return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];}

 

10. For processed properties, a dictionary cache is generally required to define the properties that have been cached and processed. Repeated use does not require repeated computing, and space is used for time. For example, you need to obtain the attribute name list during archiving, and then traverse the archive and block. Properties is also required for other intermediate operations. The level is limited. You are welcome to correct the error. Learn from each other. Reprinted please indicate the source

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.