Read Limboy and Casa's article, on the component development, organized a bit of thinking.
1. Why is component development needed?
A product, in the beginning, because the business is simple, usually directly in a project development. This way, in the initial stage of the product, there is no problem, but also can effectively guarantee the development efficiency. But as the business continues to grow, the number of codes continues to grow, and the development team grows, and the final module relationships evolve as shown:
As you can see, this single engineering development model has some drawbacks:
- Coupling between modules is critical (the module refers to a larger granularity of business functions.) For example, according to the Homepage tab, we can be divided into four modules: conversation, contacts, Discovery, I). The sample code snippet is as follows:
-(void) GOTOFILEDETAILVC {
Openfileviewcontroller *VC = [[Openfileviewcontroller alloc] Initwithfilemodel:model]; [Self.navigationcontroller PUSHVIEWCONTROLLER:VC Animated:yes];
}
The above approach is not a problem at the beginning, but when the project gets bigger, each module is dependent on the other modules.
- Merging code is prone to conflict (especially Xib, Storyboard, project files, if a large product is to use Storyboard to develop the page, especially a few modules shared a Storyboard, that in the merging of the code can only be self-blessing) ;
- Business Party development is not efficient (only concerned about the development of their own business modules, but to compile the entire project, and other irrelevant code to blend together).
2. How do I implement the component?2.1 Middleware-based target-action (recommended)
From the first part, we know the problem of the single project development model, here we will use the middleware-based target-action approach to decouple the relationship between the business modules, first look at the final structure diagram:
From what you can see:
- All business modules are completely isolated and have no dependencies;
- The business module relies on the category of the middleware module.
But from there, you may ask two questions:
- After the component, more than a middleware module, each business module more than a target class, it is really necessary to pay the cost of the component?
- Since the middleware module can be decoupled with runtime, why not use runtime decoupling directly from the business module?
The first problem: After the component, more than a middleware module, each business module more than a target class, it is really necessary to pay the cost of the component?
The answer to this question, in fact, in the first part of why to do the component said, here add a sentence:
Using runtime, in addition to the middleware does not have a compilation dependency, but also at runtime to determine the processing component does not exist, the code snippet is as follows:
So the middleware is independent of any business module, and the caller and the middleware module can be used alone.
Second question: Since the middleware module can be decoupled with runtime, why not directly in the business module to use runtime decoupling?
Take a look at the code that calls business module B directly using runtime in business module A:
Class cls = nsclassfromstring (@ "goftargetbmodule"*REVIEWVC = [CLS Performselector:nsselectorfromstring (@ "actionbviewctrlwithparam:") withobject:@{ @"title":@ " module B"}]; [Self.navigationcontroller PUSHVIEWCONTROLLER:REVIEWVC Animated:yes];
There are a few problems with this invocation method:
- When calling, writing code is not prompt, writing is more troublesome, error prone.
- The number of parameters and type limit of the runtime method, thekey value in the Nsdictionary what is not clear.
- The compiler plane does not depend on module B, but it is called directly here, and the program collapses directly without introducing the called component.
Now let's take a look at the specifics of the implementation from the code of several key classes. is the file structure and flowchart of the demo:
First, the middleware class Gofmediator, the. h file for this class is declared as follows:
@interfaceGofmediator:nsobject+(instancetype) sharedinstance;/** * Remote call * * @param URL URL (Unified format example: GOF://TARGETA/ACTIONB?ID=1234&NAME=LEEGOF) * * @return yes/no*/-(BOOL) Performremoteactionwithurl: (Nsurl *) URL;/** * Local call * * @param target Responder * @param action action * @param params parameter * * @return ID type*/- (ID) Performnativewithtarget: (NSString *) Target action: (NSString*) Actionparams:(Nsdictionary *)params;@end
Provides a remote call and local call method, where the URL of the remote invocation method, preferably a fixed format, so that can be unified parsing and jumping.
Next, look at the caller's code, so it's easy to trace it.
Uiviewcontroller *VC = [[Gofmediator sharedinstance] mediatorbviewcontroller];[ Self.navigationcontroller PUSHVIEWCONTROLLER:VC Animated:yes];
The caller used the gofmediator mediatorbviewcontroller method and continued to see the implementation of this method:
-(Uiviewcontroller *) mediatorbviewcontroller{Uiviewcontroller*viewcontroller = [Self performnativewithtarget:@"B"Action@"Bviewctrlwithparam:" params:@{@"title":@"Module B"}]; if([Viewcontroller Iskindofclass:[uiviewcontrollerclass]]) { returnViewcontroller; } Else //Handling Exceptions { returnNil; }}
As can be seen, in the implementation of the above method, called the Gofmediator Local call method to generate Viewcontroller, the local calling method (the article posted above the method code) is through the runtime, the final call the Actionbviewctrlwithparam method of Goftargetbmodule.
-(Uiviewcontroller *) Actionbviewctrlwithparam: (Nsdictionary *) param{ *VC = [[Gofbviewcontroller alloc] initwithtitle:param[@ "title"]; return VC;}
In this case, the Gofbviewcontroller instance is eventually generated and returned.
"Summary": This scheme, the component communicates through the middleware, the middleware through the runtime decoupling calls the business component's target-action, separates each business component interface code through the category .
2.2 URL-based registry method and Protocol-class registry
This is the way of Mushroom street, the details can refer to Li Zhong's two articles.
The modular way of Mushroom Street app
Mushroom Street APP's Modular Road • Cont.
As above, let's look at the structure diagram:
Through, we can see three points:
- There is no dependence between the business modules, independent of each other;
- The URL registration module (middleware module) does not depend on any other modules;
- Each business module and caller relies on the URL registration module.
This is seen from the surface of the structure diagram, below we analyze from the code angle, from the code we can see more. is the file structure and flowchart of the demo:
First, let's look at the key code for the registration URL:
+ (void) initcomponent{ [[Gofrouter sharedinstance] Registerurlpattern:@ "gof:// Aviewcontroller/:title" tohandler:^ID(ID param) { *VC = [[ Gofaviewcontroller Alloc] initwithtitle:param[@ "title"]; return VC; }];}
Here, the effect of registration is to give a cache dictionary to the Gofrouter class, adding a URL and corresponding callback function.
Then we look at the caller's key code:
Uiviewcontroller *VC = [[Gofrouter sharedinstance] OpenURL:@ "gof://aviewcontroller/a module " withparam:@{@ "name"@ "Gof"}]; [Self.navigationcontroller PUSHVIEWCONTROLLER:VC Animated:yes];
From the above description, we can see that there are several problems in this way:
- The available URLs need to be managed. Mushroom Street is to have a unified backstage to manage;
- Each URL needs to be registered, and stored in memory, so that more URLs, there will be memory problems;
- The parameter is a dictionary, how to pass, what field to pass, the business component needs to explain and manage this dictionary.
3. What are the components of the actual project?
In a real-world project, we need to consider the following issues for component development:
- How do I split components?
- What is the way to implement communication between components?
- How to do continuous integration of code?
- The issue of harmonization and harmonization of each end.
First question: How do I split components?
For component development, the most important thing is to component the various business modules, and of course, some of the basic components need to be considered, then in the actual project, the component can be considered to design:
About the underlying components:
- According to the function division, does not involve the business, may understand as the third party library;
- Provide the appropriate APIs for business components to use.
About Business components:
- The business components are independent of each other, and there is no dependency relationship;
- Calls between business components are implemented through middleware components;
- There should be a model between business components.
Second question: What is the way to implement communication between components?
This problem in the second part of the content has been described in detail in two ways to achieve communication between components, I would recommend the first way: Middleware-based target-action
The third question: How do you do continuous integration of code?
Consider using Submodule/subtree, or consider using a private library of cocoapods to manage components.
Question Fourth: harmonization and harmonization of each end.
There are few products in general, and the problem of components is considered at the outset. Because the component will bring development cost, when it is more harmful than the benefit, we usually choose the traditional single engineering development mode, to quickly develop the product. With the continuous development of the product business and rapid iteration, the size of the development team is growing, will be a burst of problems mentioned earlier, this time we will consider some of the improvements, this is the component of the development program. However, the modular development solution, on the one hand, the client needs unified design and planning, then the corresponding, the other departments should also cooperate:
- Server: Unified management of interfaces by component partitioning. It is best to have a unified space, the client, the server in accordance with the components, write the corresponding documents, so as to achieve the continuity of team development. In addition, each component team, to designate the corresponding responsible person, each component preferably has two people, the modification of a component, preferably by the person in charge, if it is modified by the other component team, must be approved by the owner of the component, and the code needs review;
- Design/Product: Unify the product planning, unify the interface style, assist to draw some common UI.
- Test: Since the component development is generally in the product relatively mature stage, then the product design and development of the component, it is necessary to test the product to do a full-scale regression test.
Some thoughts on the component development