Decoupling between ios service modules

Source: Internet
Author: User

Decoupling between ios service modules

* This article requires a little runtime knowledge. If you do not know runtime, quick understanding of Runtime of Objective-C:

Http://mp.weixin.qq.com? _ Biz = MzIxNDI0OTAzOQ ==& mid = 403005635 & idx = 1 & sn = 71375cb0dee51487c90087d488ff59fe

Problem:

An app is usually composed of many modules, and all modules are inevitably called each other. For example, a reading management software may have bookshelves, user information, book details, and other modules, from user information-the book I read, you can open the book details. In the book details-the bookshelves, you can open the bookshelves. In general, we may achieve this:

/* User information module */# import "UserViewController. h "# import" BookDetailViewController. h "@ implementation UserViewController // jump to book details + (void) gotoBookDetail {BookDetailViewController * detailVC = [[BookDetailViewController alloc] initWithBookId: self. bookId]; [self. navigationController. pushViewController: detailVC animated: YES];} @ end

The initial stage of the project is good, fast, simple enough. However, when the project develops to a certain extent, the problem arises. Every module cannot be separated from other modules and the dependencies are stuck together:

 

Figure 1: module dependency. Arrows indicate dependencies. For example, Discover depends on BookDetail.

Solution:

In this case, the most direct method is to add a middleware. Each module jumps to the middleware for management. In this way, all modules only rely on this middleware. But how does middleware call other modules? Well, middleware will depend on all modules again. It seems that, apart from increasing the complexity of the Code, it does not actually solve any problem.

Code for introducing middleware:

/* User information module */# import "UserViewController. h "# import" Mediator. h "@ implementation UserViewController // jump to book details + (void) gotoBookDetail {[Mediator gotoBookDetail: self. bookId];} @ end/* middleware */# import "Mediator. h "# import" BookDetailViewController. h "@ implementation Mediator // jump to book details + (void) gotoBookDetail :( NSString *) bookid {BookDetailViewController * detailVC = [[BookDetailViewController alloc] initWithBookId: bookId]; [self. navigationController. pushViewController: detailVC animated: YES];} @ end

Introduce the dependency of middleware:

Figure 2: Introduce the dependency of Middleware

Is there a way to perfectly solve this dependency? We hope that each module is independent from each other, and each module can be compiled and debugged independently by different people from the project. The following solution solves this problem through the transformation of the middleware. the dependencies between the resolved modules are as follows:

Figure 3: Ideal inter-module dependency

 

Implementation Method:

 

Let's take a practical example.

Please download the demo first and open the: https://github.com/zcsoft/ZC_CTMediator

 

First, let's take a look at the directory structure and have a general understanding of the entire project's organizational structure. Then, we will analyze the specific implementation in detail by combining the structure diagram and the description of each class and the project code:

 

 

Directory structure:

 

[CTMediator project directory]

|

|-[CTMediator]

|-CTMediator. h.m

|-[Categories]

|-[ModuleA]

|-CTMediator + CTMediatorModuleAActions. h. m

|

|-[DemoModule]

|-[Actions]

|-Target_A.h.m

|-DemoModuleADetailViewController. h. m

|

|-AppDelegate. h. m

|-ViewController. h. m

Note:

[CTMediator]

Middleware responsible for redirection. All inter-module redirects are completed through this module.

 

[DemoModule]

For example, we want to jump from other services (ViewController. h.m) to this business module.

 

In this demo, we aim to jump from other services (in ViewController. h.m) to the DemoModule business module.

 

 

Reference relationships of all modules

Figure 4: Reference relationship of modules in the demo

Because the demo only uses ViewController. h. m to jump to the DemoModule module, so you only need ViewController. h. m depends on CTMediator. The call from CTMediator to the DemoModule module is completed at runtime (the Blue Line in the image) and does not require dependency protection in the code. That is to say, if a module does not need to jump to other modules, it does not need to rely on CTMediator.

Running time sequence:

Figure 5: hiding the reference relationship of implementation details in the module

Call link Overview:

First by ViewController. h. m initiates a call request to the CTMediator. The CTMediator calls the DemoModule of the target module through runtime. The DemoModule of the target module creates its own instance based on parameters and returns the instance to the CTMediator, CTMediator is returning this instance to ViewController. h. m (ViewController. h. m does not need to know the specific type of the instance, but only needs to know that it is a subclass of UIViewController. h. m decides how to display the DemoModule.

Figure 6: complete call relationship

Call relationship details:

1: ViewController. m initiates a call request to CTMediator (CTMediator + CTMediatorModuleAActions. m ). ViewController. m-57 line

 

 

UIViewController *viewController = [[CTMediator sharedInstance] CTMediator_viewControllerForDetail];

 

 

2: CTMediator + CTMediatorModuleAActions. m calls CTMediator through defined parameters. Because CTMediator + CTMediatorModuleAActions is an extension of CTMediator, you can directly use self to call the implementation of CTMediator. CTMediator + CTMediatorModuleAActions. m-row 23

 

UIViewController *viewController =        [self performTarget:kCTMediatorTargetA                     action:kCTMediatorActionNativFetchDetailViewController                     params:@{@"key":@"value"}];

 

 

3: CTMediator initiates actual calls based on the targets and parameters passed by CTMediator + CTMediatorModuleAActions. m. This call relationship is completed at runtime. Therefore, the Code does not need to depend on the called user. If the called user does not exist, it can be processed at runtime. CTMediator. m-93 line

 

 

return [target performSelector:action withObject:params];

 

 

4/5: Target_A creates an instance of the DemoModuleADetailViewController type (this instance is created by Target_A through alloc/init of the DemoModuleADetailViewController class ). Target_A.m-20 line

 

 

DemoModuleADetailViewController *viewController = [[DemoModuleADetailViewController alloc] init];

 

6: Target_A returns the created instance to CTMediator. m (start with runtime, step 3), and CTMediator. m does not know the specific type of this instance, nor does it perform any parsing operations on this class, so CTMediator. m has no reference relationship with the returned instance. Target_A.m-23 line

 

7: CTMediator. m returns the Instance obtained in Step 6 to CTMediator + CTMediatorModuleAActions. m (step 2 at the time of initiation ). CTMediator. m-93 line

 

8: CTMediator + CTMediatorModuleAActions. m processes the instances returned in Step 7 as UIViewController. Then, it judges at runtime whether the instance type is UIViewController (not a subclass of UIViewController ). Then, the obtained UIViewController is handed over to the caller ViewController. m (in which way ViewController. m Displays the UIViewController. m ). CTMediator + CTMediatorModuleAActions. m-line 29

 

 

The functions of all classes are as follows:

 

CTMediator. h. m

Function: Specify the target (Class Name) + action (action, method name), and provide a dictionary type parameter. CTMediator. h.m checks whether the target-action can be called. If yes, it is called. This function is dynamically implemented through runtime, so it is used in the CTMediator. h. m implementation does not depend on any other modules, nor does it need to know the specific features of target-action, as long as the target-action exists, it will be executed (the specific target-action function is the responsibility of the DemoModule itself ).

CTMediator. h actually provides two methods, respectively processing the url call and the target-action call. If the url method is used, the url is automatically converted to the target-action.

 

CTMediator + CTMediatorModuleAActions. h.m

Function: extends the CTMediator to manage the actions that jump to the DemoModule module. When other modules want to jump to the DemoModule module, they are implemented by calling the method of this class.

However, this class does not actually perform the jump action. It is just for the CTMediator. h. m class encapsulation, so that users do not need to care about using CTMediator. h. the target name and action name required by m to jump to the DemoModule module.

 

'Ctmediator. h. m' + 'ctmediator + CTMediatorModuleAActions. h. m' together forms a jump of the DemoModule, and it does not depend on the DemoModule in the Code. Whether the DemoModule provides the corresponding jump function is only reflected in whether it can jump normally during running. So far, the middle layer of CTMediator is completely independent. Other modules do not need to be registered in advance, and the CTMediator does not need to know the implementation details of other modules. The only association is to specify the correct target + action and correct parameters in 'ctmediator + CTMediatorModuleAActions. h. M', and these actions and parameters only depend on Target_A.h.m. The correctness of the action and parameter is only checked at runtime. If the target or action does not exist, you can perform corresponding processing in 'ctmediator. h. M. Both: The CTMediator can be compiled and run without relying on any modules.

 

Target_A.h.m

Provides an external interface to jump to the DemoModule module, with CTMediator + CTMediatorModuleAActions. h. m corresponds to each other. It can be said that it is only used for CTMediator + CTMediatorModuleAActions. h. m provides services, so in the implementation of CTMediator + CTMediatorModuleAActions. h. for m, you only need to refer to Target_A.h.m, which is simple enough and does not need documents to assist in the description. When other modules want to jump to this module, they cannot be directly implemented through Target_A.h.m, but through CTMediator + CTMediatorModuleAActions. h.m. In this way, the modules are independent from each other, and the CTMediator is required only when you need to jump to other modules.

 

DemoModuleADetailViewController. h. m

The main view of the DemoModule module. In this example, the module is redirected from ViewController. h. m.

 

AppDelegate. h. m

APP portal. This class is used when a program jumps out of the application through Scheme.

 

ViewController. h. m

The main view of the APP. You need to jump to the DemoModule module here.

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.