The Coordinator model has been introduced in this article and related English articles are listed in it. Coordinator mode is more suitable for a good architecture from the beginning. For old projects, a relatively good migration scheme is proposed for reference.

How to transfer

In most cases, we import an AVC.m file directly into another BVC.h file, and then construct B in one of A’s jump methods, push or present.

// AVC.m
import "BVC.h"

- (void)onClickPushB{
BVC *b = [BVC new];
[self.navigationController pushVC:b];
}

Copy the code

The coupling happens because B is directly constructed in A, so we first have to get this logic out of the delegate pattern.

// AVC.h
@protocol ACoordinatorDelegate 
-(void)AvcOnClickPushB:(UIViewController *)vc;
@end

@property (weak) id<ACoordinatorDelegate> delegate;
Copy the code

The original call is changed to this, and there is no need to import vbC.h:

- (void)onClickPushB{
[self.delegate AvcOnClickPushB:self];
}
Copy the code

Now we need to assign A’s delegate where WE constructed A, because I want to make as few changes as possible (without changing the original jump logic), so A’s delegate is still A.

// tabbarController.m

AVC *a = [AVC new];
a.delegate = a;
Copy the code

Create A category file to implement the ACoordinatorDelegate protocol.

@implementation AVC (ACoordinatorDelegateIMP)
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = b;
[self.navigationController pushVC:b];
}
@end
Copy the code

One more line of code than the original implementation (if BVC also needs to jump). At this time, AVC has eliminated the coupling between controllers and improved the scalability and reusability.

A traditional improvement on direct coupling is to design a new class, Router, into which all jump methods are grouped, and all jumps call Router methods. Once you’ve done that, you can also use the Router, make the Router follow the protocol, and move all the methods in the category to the Router. Change self to VC.

@implementation Router 
#pragma mark - ACoordinatorDelegate
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = self;
[vc.navigationController pushVC:b];
}
@end
Copy the code

The same is true if you are migrating from an existing Router or CTMediator.

When migrating to Coordinator mode, you simply add the Coordinator class, move the Coordinator methods to the corresponding.m, and assign the delegate to self.

@implementation ACoordinator 

- (void)start{
AVC *a = [AVC new];
a.delegate = self;
[self.rootVC pushViewController:a animated:NO];
}

#pragma mark - ACoordinatorDelegate
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = self;
[self.rootVC pushViewController:b animated:NO];
}
@end
Copy the code

Of course, there is also a global AppCoordinator, which is typically held by an AppDelegate as a startup entry.

conclusion

This migration scheme is in line with the open and closed principle. No matter the Router, CTMediator, or Coordinator is used in the end, an indirect layer is added and only the implementation is changed. The modification of the original code is relatively small. And even without an intermediary layer of indirection, just separating out categories like above makes the code a lot cleaner.

Finally, the Coordinator mode on Github is basically implemented by Swift. Here is an OC implementation for reference.