MGJRouter Implementation principle of the Mogujie component

Plan a url – block

This is a way of calling between pages in the application of moguji street. By registering the service provided by the component at startup, the url used by the calling component and the service block provided by the component are stored in memory. When using a component’s service, the corresponding block is found through the URL and then the service is obtained.

registered

[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
    NSNumber *id = routerParameters[@"id"];
    // create view controller with id
    // push view controller
}];
Copy the code

Call:

  • Url parameter passing is limited, only regular string parameters can be passed, not non-conventional parameters, such as UIImage, NSData, and so on
  • Failure to distinguish between local and remote calls, especially remote calls, results in some functionality limitations due to url parameters
  • The components themselves depend on middleware, and decentralized registration allows for more coupling

Protocol -class

To solve the problem of solution 1, Mogujie proposed another componentization solution, which is to define the service interface through the protocol. The component provides the service defined by the interface through the implementation of this interface. The specific implementation is to make a mapping between the protocol and the class, and save a mapping table in memory. The protocol is used to find the corresponding class to obtain the required service.

Registration:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA]
Copy the code

call

[ModuleManager classForProtocol:ProtocolA]
Copy the code

Mogujie’s solution does solve the problem of not passing unconventional parameters in Solution 1, making inter-component calls more convenient, but it still doesn’t solve the problem of component dependency on middleware, the problem of maintaining mapping tables in memory, and the problem of decentralized calls to components. The design concept is similar to scenario 1, which is to add a wrapper layer to the component and then call it to the consumer.

Solution 3. Target-action

Casa provides services to the outside world by wrapping a wrapper around the component, and then the caller uses the services by relying on middleware. Among them, the middleware calls the service of the component through Runtime, which is the decoupling in the true sense, and also the core of the solution. The specific implementation process is to encapsulate a layer of target objects for components to provide external services, which will not cause invasion to the original components; Services are then provided to callers by implementing middleware categories, so that consumers only rely on middleware and components do not. That is, each component creates a target class (maintained by the component developer) that internally defines the actions (methods) that the component exposes. When communicating with a component, the essence is to call a specific target-action method. Target class class name must begin with Target_, Target_A, for example, the action method name must begin with Action_, such as Action_nativeFetchDetailViewController. Note that the exposed Target class is not a specific implementation of the component. It is just for the convenience of the caller. The target class implementation file will introduce the component’s header file to implement the functions in the declaration file to invoke the component.

The consumer only depends on the middleware, and the middleware does not depend on the components, which is true decoupling. However, the problem of casA’s solution is hardcode. There is hardcode in the category of middleware. The explanation of CasA is that when calling between components, it is best to demodel, so hardcode is inevitably introduced, and all hardcode only exists in the category. Aiming at this problem, a proposal, make all the model a componentized sink, and let all the components has free access to the model, but in my opinion, although this solution can solve the problem of transfer model dependence between components, but in order to solve this problem, the whole model layer directly componentization after exposed to all of the components, Easy to cause data leakage, the cost is a little big. In view of this problem, after discussion with netizens, we agree that the dictionary is used to pass data when calling between components, and the model is used to pass data when calling within components, which not only reduces the coupling of data between components and model, but also facilitates the convenience of using model to pass data within components.