Step 1 of Dictionary to Model: Designing a Model
- Model properties, usually one-to-one correspondence with key s in a dictionary
- Question: Is it slow to generate model properties one by one?
- Requirements: Can you automatically generate corresponding attributes from a dictionary?
- Solution: Provide a categorization specifically to generate corresponding attribute strings from a dictionary.
@implementation NSObject (Log)
// Print Attribute String Automatically
+ (void)resolveDict:(NSDictionary *)dict{
// Stitching Attribute String Code
NSMutableString *strM = [NSMutableString string];
// 1. Walk through the dictionary, take out all key s from the dictionary, and generate corresponding attribute codes
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// Type often changes, pull out
NSString *type;
if ([obj isKindOfClass:NSClassFromString(@"__NSCFString")]) {
type = @"NSString";
}else if ([obj isKindOfClass:NSClassFromString(@"__NSCFArray")]){
type = @"NSArray";
}else if ([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")]){
type = @"int";
}else if ([obj isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){
type = @"NSDictionary";
}
// Property String
NSString *str;
if ([type containsString:@"NS"]) {
str = [NSString stringWithFormat:@"@property (nonatomic, strong) %@ *%@;",type,key];
}else{
str = [NSString stringWithFormat:@"@property (nonatomic, assign) %@ %@;",type,key];
}
// Wrap lines automatically whenever a property string is generated.
[strM appendFormat:@"\n%@\n",str];
}];
// Print out the stitched strings.
NSLog(@"%@",strM);
}
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
Step 2 of Dictionary to Model (Mode 1): How KVC does Dictionary to Model (previously used)
+ (instancetype)statusWithDict:(NSDictionary *)dict
{
Status *status = [[self alloc] init];
[status setValuesForKeysWithDictionary:dict];
return status;
}
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
-
Disadvantages of KVC Dictionary-to-Model: It is necessary to ensure that the attributes in the model correspond to the keys in the dictionary one-to-one.If inconsistent, [setValue:forUndefinedKey:] is called to report an error that the key cannot find.
-
Analysis: Attributes in the model do not correspond to key s in the dictionary, and the system will call setValue:forUndefinedKey:Error.
-
Solution: Rewrite the setValue:forUndefinedKey:, override the system's methods, and you can continue to use KVC, the dictionary to model.
Step 2 of Dictionary to Model (Mode 1): Dictionary to Model using Runtime
- Ideas: At run time, traverse all the attributes in the model, find the key in the dictionary according to the attribute name of the model, take out the corresponding values, and assign values to the attributes of the model.
- Step: Provide a NSObject classification, a specialized dictionary to model, through which all models can be converted in the future.
Implementation code:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Parse Plist file
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];
NSDictionary *statusDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
// Get Dictionary Array
NSArray *dictArr = statusDict[@"statuses"];
// Automatically generate attribute strings for models
// [NSObject resolveDict:dictArr[0][@"user"]];
_statuses = [NSMutableArray array];
// Traverse Dictionary Array
for (NSDictionary *dict in dictArr) {
Status *status = [Status modelWithDict:dict];
[_statuses addObject:status];
}
// test data
NSLog(@"%@ %@",_statuses,[_statuses[0] user]);
}
@end
@implementation NSObject (Model)
+ (instancetype)modelWithDict:(NSDictionary *)dict
{
// Idea: Walk through all the properties in the model - "Use Runtime
// 0. Create the corresponding object
id objc = [[self alloc] init];
// 1. Use runtime to assign values to member attributes in objects
// class_copyIvarList: Gets all member properties in a class
// Ivar: The meaning of a member's attribute
// First parameter: Indicates which class to get member properties from
// Second parameter: Indicates how many member attributes this class has, passes in an Int variable address, and automatically assigns a value to this variable
// Return value ivar *: refers to an array of Ivars that puts all member attributes in one array and gets them all from the returned array.
/* Like the following
Ivar ivar;
Ivar ivar1;
Ivar ivar2;
// Define an array of Ivars a
Ivar a[] = {ivar,ivar1,ivar2};
// Point an Ivar * pointer to the first element of the array
Ivar *ivarList = a;
// Accessing the first element of an array based on a pointer
ivarList[0];
*/
unsigned int count;
// Gets all member properties in a class
Ivar *ivarList = class_copyIvarList(self, &count);
for (int i = 0; i < count; i++) {
// Remove the corresponding member properties from the array based on the corner label
Ivar ivar = ivarList[i];
// Get member property name
NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
// Processing member property names - > key s in dictionaries
// Intercept from the first corner
NSString *key = [name substringFromIndex:1];
// Find the corresponding value in the dictionary based on the member property name
id value = dict[key];
// Secondary conversion: If there is a dictionary in the dictionary, you also need to convert the corresponding dictionary into a model
// Judge if value is a dictionary?
if ([value isKindOfClass:[NSDictionary class]]) {
// Dictionary to Model
// Get the class object of the model and call modelWithDict
// The class name of the model is known, that is, the type of member property
// Get member property type
NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
// This @'@"User\""type-"@ "User" is generated in the OC string \"->", \ is escaped and does not occupy characters
// Clipping type string
NSRange range = [type rangeOfString:@"\""];
type = [type substringFromIndex:range.location + range.length];
range = [type rangeOfString:@"\""];
// Which corner label to clip to, excluding the current one
type = [type substringToIndex:range.location];
// Generate class object from string class name
Class modelClass = NSClassFromString(type);
if (modelClass) { // There is a corresponding model to rotate
// Convert Dictionary to Model
value = [modelClass modelWithDict:value];
}
}
// Level 3 conversion: NSArray is also a dictionary, converting dictionaries in arrays into models.
// Is the value an array?
if ([value isKindOfClass:[NSArray class]]) {
// Determine if the corresponding class has a protocol for converting dictionary arrays to model arrays
if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
// Convert to id type to call any object's method
id idSelf = self;
// Get the model for the dictionary in the array
NSString *type = [idSelf arrayContainModelClass][key];
// Generate model
Class classModel = NSClassFromString(type);
NSMutableArray *arrM = [NSMutableArray array];
// Traverse dictionary arrays to generate model arrays
for (NSDictionary *dict in value) {
// Dictionary to Model
id model = [classModel modelWithDict:dict];
[arrM addObject:model];
}
// Assign model array to value
value = arrM;
}
}
if (value) { // Value is required to assign values to the properties of the model
// Using KVC to assign values to attributes in a model
[objc setValue:value forKey:key];
}
}
return objc;
}
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
Personal summary:
To achieve automatic conversion of dictionaries and models: first, according to the implementation model of the model......
(The core is that you can iterate through each attribute in the dictionary, which is used by the Daniel Framework in json parsing, including MJEXtension,YYModel, and jsonModel, which all convert json into a dictionary and then iterate through each attribute in the dictionary to perform a modle conversion).
Basically, the mainstream json to model is indispensable. Dictionary to model substitution is performed by using the runtime method of dynamically getting attribute names of attributes. The most efficient (and time-consuming) dictionary to model is KVC. Other dictionary to model is handled by the key and value of KVC. The key and value in json are obtained dynamically. Of course, in the process of conversion, the third-party framework needs to make some blank decisions.Ah, mosaic logic, KVC to model.
Regardless of JsonModle,YYKIt,MJextension is indispensable [xx setValue:value for Key:key]; this code, if you don't trust it, can be searched, which is the core method of dictionary-to-model.