Making address:YBModelFile
A line of code automatically generates a Model file, which can be used by dragging it into the project.
preface
When a network data is more complex, it often needs some effort to create the corresponding data Model, the author is suffering from manual Model creation pain, decided to make a tool to create Model files automatically.
In order to reduce the cost of tool development, directly based on the iOS system library to do. If it is a tool on the Mac, there will be some technical problems, such as inconvenient to use the dynamic link library of iOS programs, weak to deal with some types in iOS, and the tool does not know the information of the target project, it will be very inconvenient to judge the repeated class name and read the project information.
This article explains the design ideas and technical details of YBModelFile.
A, sample
To make it easier to understand, put a JSON:
{
"name":"jack"."address": {"city":"Beijing"."location":"x,x"},
"orderList": [{"id": 1,"goods":"Mobile phone"}, {"id": 2."goods":"Computer"}}]Copy the code
Classes can be built as follows:
@interface PersonAddressModel : NSObject
@property (nonatomic, copy) NSString *city;
@property (nonatomic, copy) NSString *location;
@end
@interface PersonOrderListModel : NSObject
@property (nonatomic, copy) NSString *goods;
@property (nonatomic, assign) NSInteger *id;
@end
@interface PersonModel : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) PersonAddressModel *address;
@property (nonatomic, copy) NSArray<PersonOrderListModel *> *orderList;
@end
Copy the code
Here’s how tools can build these things automatically (and some implementations of.m files, of course).
2. Build a multi-fork tree
The tool needs to build custom classes from JSON data, so as shown in the example, building a class must know its class name and all its attributes, and the attributes of a class can be another class, or an array of wrapped classes…
It’s easy to think of divide-and-conquer, where the data is localized so that it can be structured as a tree:
In this tree structure, the Custom Class is the Class that the tool needs to build, while NSString, NSNumber, NSInteger and so on already exist and need not be built. It is worth noting that the NSArray attribute contains a Class, which may be a system Class or a Custom Class.
To be clear, the child node is required as an attribute of the parent node when the Class is built. Custom classes have child nodes, while system types such as NSString do not.
From this, you can build such a tree structure by iterating through the JSON transformed dictionary. A node is represented in the tool as follows:
@interface YBMFNode: NSObject /** Node type */ @property (nonatomic, assign) YBMFNodeTypetype; /** child node */ @property (nonatomic, strong) NSMutableDictionary<NSString *, YBMFNode *> *children; . @endCopy the code
The child nodes are stored through a dictionary, and the key represents the field name of the corresponding node in JSON, which is used as the attribute name when building the class.
Class name and attribute name processing
As you build the tree, you need to deal with both class and attribute names. As you can see from the example above, the property name can take the key directly from the JSON; The class name can be added with a key from the parent node’s class name (e.g. PersonModel + Address = PersonAddressModel).
It looks like the problem is solved, but there’s actually a whole bunch of judgments that need to be made to make sure that the class names and the attribute names are valid.
Class name handling:
- Filter out invalid characters in the key.
- Convert the key snake to a hump.
- Parent node class name + key + suffix = current class name
- The weight of class name: one is the existing class in the project catalog and system library; The second is the classes to be created during a program’s life cycle. What do you mean by a class to be created? In fact, in a program run, through the tool to create a new class, because in this program run these new classes have not been added to the project, so can not be obtained through the code. I can easily detect duplication by applying a static hash container to put the new class to be created.
- Class name repeat processing: when you know that the class name is repeated, the processing scheme is a lot of, I add a number at the end of the class name, cyclic accumulation of this number until the same name.
- Why not do class reuse: first of all, personal understanding of the specification, data model classes better not reuse; Secondly, technically, due to automatically create the name of the class every time cannot forecast, to determine whether a class can reuse only through iterate through all the attributes to compare, and known to stipulate the scope of reusable classes is bad, is also a big challenge for time and space complexity, so the author thinks that do not do such reuse anything too big.
- Why you don’t filter reserved words: Typically, the tool requires the user to pass in the name of the main Model, which usually starts with a capital letter, and subsequent classes extend the class name and concatenate suffixes, so in theory it directly avoids conflicts with reserved words (uppercase reserved words like YES and NO).
- Problem: Consider limiting the length of the class name or using a class name extension strategy that is independent of the key, but there are obvious drawbacks to either approach.
Attribute name handling:
- Filter out invalid characters in the key.
- If the same name as the reserved word, all caps.
- If the prefix has special characters (e.g
Init, new
), uppercase the special character part. - If the prefix contains a number, prefix it with “_”.
- Attribute name weighting: if you have two identical attributes in a class, you might say that the json object does not have the same field name
order>list
andorder? list
Both after treatmentorder_list
); The second case is the same name as the attribute of the parent class, so the author traverses all the instance variables of the parent class and adds them at the same timeNSObject
Properties of the protocol (if the base class of the data model is notNSObject
Situations that are not covered by the protocol name may occur. - Attribute name duplication: Same name duplication.
4. Separation of algorithm logic
Because of the need to implement dynamic class file distribution, the code involved is different when two classes are placed together than when two classes are separated (for example, two classes together need only one header annotation and do not need another header import).
So the tool blocks the code in.h and.m into different processing units, such as annotations at the top of the file, import file dependencies, and actual business code. Based on multi-tree model, dynamic code insertion can be carried out flexibly through deep search or wide search, so as to achieve flexible control and provide a powerful data structure support for existing functions or functions to be done in the future.
At the same time, in order to expand and customize, the author creates several protocols and provides default implementation, so that users can flexibly replace local algorithms:
/** name handler */ @property (nonatomic, strong) id<YBMFNameHandler> nameHander; / / @property (nonatomic, strong) id<YBMFFileNoteHandler> fileNoteHander; /**.h file code handler */ @property (nonatomic, strong) id<YBMFFileHHandler> fileHHandler; / / @property (nonatomic, strong) id<YBMFFileMHandler> fileMHandler; /** Code format processor */ @property (nonatomic, strong) id<YBMFCodeForParentHandler> codeForParentHandler;Copy the code
Fifth, class splitting strategy
With all that mentioned above, building code strings from.h or.m files is a breeze.
Classes are split into multiple files
Implement a class corresponding to a group. H/m file strategy, directly through a depth first search, in the process of assembly code files and create a file, but the processing logic is after order, that is, the deeper hierarchy tree to create more, this is for the sake of a dependent class is always ahead of this class is created, when midway abnormal, have created files can run effectively.
Classes are concentrated in one file
Most of the time, we want to put a DATA model class under JSON into a file. Thanks to the separation of algorithm logic modules, it is easy to use depth-first search to dynamically build the required code and assemble it into a reasonable structure. In this case, I still use post-processing, so that a class depends on the class always above it, so that in a file there is no need to use @class AnyClass; Here we go.
TODO: Class separation granularity control
Consider complex scenarios where you may need to split files on demand, such as 100 classes that need to be divided into 10 groups of. H /.m files. There are three ways we can think of:
- For multi-fork tree, the file is divided according to the hierarchy, and the classes in the first layer are divided into a file. The disadvantage of this method is that all the classes in a file are brothers and there is no logical association, which is not easy to manage.
- Control by setting a maximum level, such as level 3, so that all child node classes after level 3 are merged into the level 3 class file.
- Third, in the process of deep search, the number of classes in the file is recorded. When a file reaches the number limit, a new file is created to write classes.
After the language
This tool is an effort by me to develop efficiency, and usually saves you a lot of time. I hope it will help you.
In the process of discovering requirements, designing solutions, encountering problems, and solving problems, the author seems to feel something other than technology. For an excellent engineer, the ability to solve problems efficiently and comprehensively at any time is more important than the technology itself.
✨ ✨ 😁 ✨ ✨