Skip to content

Latest commit

 

History

History
285 lines (215 loc) · 9.74 KB

RouterImplementation.md

File metadata and controls

285 lines (215 loc) · 9.74 KB

Router Implementation

To make your class become modular, you need to create router for your module. You don't need to modify the module's code. That will reduce the cost for refactoring existing modules.

Here is an example for creating router for EditorViewController.

Swift sample:

protocol EditorViewInput {
    weak var delegate: EditorDelegate? { get set }
    func constructForCreatingNewNote()
}

class EditorViewController: UIViewController, EditorViewInput {
    ...
}

Router Subclass

Create a ZIKViewRouter subclass for EditorViewController and override router's interface:

//EditorViewRouter.swift

//Declare that EditorViewController is routable
extension EditorViewController: ZIKRoutableView {

}
//Declare that EditorViewInput is routable protocol
extension RoutableView where Protocol == EditorViewInput {
    init() { self.init(declaredProtocol: Protocol.self) }
}

class EditorViewRouter: ZIKViewRouter<EditorViewController, ZIKViewRouteConfiguration> {
    //Register the router's view and protocol
    override class func registerRoutableDestination() {
        //Register EditorViewController with this router. A router can register multi views, and a view can be registered with multi router
        registerView(EditorViewController.self)
        
        //Register EditorViewInput, then you can use this protocol to get this router
        register(RoutableView<EditorViewInput>())
    }
    //Make sure all routable dependencies in this module is available.
    override class func _didFinishRegistration() {
        assert(Router.to(RoutableService<SomeServiceInput>()) != nil)
    }
    
    //Return the destination module
    override func destination(with configuration: ZIKViewRouteConfiguration) -> EditorViewController? {
        // In configuration, you can get parameters from the caller for creating the instance
        let data = // Get data from configuration
        let destination = EditorViewController(data: data)
        return destination
    }
    
    //Whether the destination from storyboard requires dependencies from external
    override func destinationFromExternalPrepared(destination: EditorViewController) -> Bool {
        if (destination.delegate != nil) {
            return true
        }
        return false
    }
    
    //Prepare the destination before performing route, and inject dependencies
    override func prepareDestination(_ destination: EditorViewController, configuration: ZIKViewRouteConfiguration) {
        //Inject dependencies for EditorViewController
    }
    
    //Check dependencies after preparing
    override func didFinishPrepareDestination(_ destination: EditorViewController, configuration: ZIKViewRouteConfiguration) {
        
    }
    
    //AOP for view Router
    override class func router(_ router: ZIKAnyViewRouter?, willPerformRouteOnDestination destination: EditorViewController, fromSource source: Any?) {
        
    }
    override class func router(_ router: ZIKAnyViewRouter?, didPerformRouteOnDestination destination: EditorViewController, fromSource source: Any?) {
        
    }
    override class func router(_ router: ZIKAnyViewRouter?, willRemoveRouteOnDestination destination: EditorViewController, fromSource source: Any?) {
        
    }
    override class func router(_ router: ZIKAnyViewRouter?, didRemoveRouteOnDestination destination: EditorViewController, fromSource source: Any?) {
        
    }
}
Objective-C Sample
//EditorViewInput.h

//Declare that EditorViewInput is routable protocol
@protocol EditorViewInput: ZIKViewRoutable
@property (nonatomic, weak) id<EditorDelegate> delegate;
- (void)constructForCreatingNewNote;
@end
@interface EditorViewController: UIViewController <EditorViewInput>
@end

Create a ZIKViewRouter subclass for EditorViewController:

//EditorViewRouter.h
@interface EditorViewRouter : ZIKViewRouter
@end
//EditorViewRouter.m

//Declare that EditorViewController is routable
@interface EditorViewController (EditorViewRouter) <ZIKRoutableView>
@end
@implementation EditorViewController (EditorViewRouter)
@end

@implementation EditorViewRouter

//Register the router's view and protocol
+ (void)registerRoutableDestination {
    //Register EditorViewController with this router. A router can register multi views, and a view can be registered with multi router
    [self registerView:[EditorViewController class]];
    
    //Register EditorViewInput, then you can use this protocol to get this router
    [self registerViewProtocol:ZIKRoutable(EditorViewInput)];
}

//Return the destination module
- (nullable EditorViewController *)destinationWithConfiguration:(ZIKViewRouteConfiguration *)configuration {
    // In configuration, you can get parameters from the caller for creating the instance
    id data = // Get data from configuration    
    EditorViewController *destination = [[EditorViewController alloc] initWithData:data];
    return destination;
}

//Whether the destination from storyboard requires dependencies from external
- (BOOL)destinationFromExternalPrepared:(EditorViewController *)destination {
    if (destination.delegate != nil) {
        return YES;
    }
    return NO;
}

//Prepare the destination before performing route, and inject dependencies
- (void)prepareDestination:(EditorViewController *)destination configuration:(ZIKViewRouteConfiguration *)configuration {
    //Inject dependencies for EditorViewController
}

//Check dependencies after preparing
- (void)didFinishPrepareDestination:(EditorViewController *)destination configuration:(ZIKViewRouteConfiguration *)configuration {
    
}

//AOP for view router
+ (void)router:(nullable ZIKViewRouter *)router willPerformRouteOnDestination:(EditorViewController *)destination fromSource:(id)source {
    
}
+ (void)router:(nullable ZIKViewRouter *)router didPerformRouteOnDestination:(EditorViewController *)destination fromSource:(id)source {
    
}
+ (void)router:(nullable ZIKViewRouter *)router willRemoveRouteOnDestination:(EditorViewController *)destination fromSource:(id)source {
    
}
+ (void)router:(nullable ZIKViewRouter *)router didRemoveRouteOnDestination:(EditorViewController *)destination fromSource:(id)source {
    
}

@end

The router subclass can set generic parameters when inheriting from ZIKViewRouter. See Type Checking.

Advantages of Router Subclass

  • Support multi protocols in one router
  • Support multi classes of destination
  • You can add custom actions in the subclass, such as custom transition and custom AOP
  • Support AOP of view transition
  • Handle custom events in the router
  • Add other custom features with your router subclass

Simple Router

If your module is very simple and don't need a router subclass, you can just register the class in a simpler way:

ZIKAnyViewRouter.register(RoutableView<EditorViewInput>(), forMakingView: EditorViewController.self)
Objective-C Sample
[ZIKViewRouter registerViewProtocol:ZIKRoutable(EditorViewInput) forMakingView:[EditorViewController class]];

The destination will be created by[[RegisteredClass alloc] init].

Note: You should not use this method if the class is pure swift class, or it has custom designated initializer. It will crash because the class couldn't create instance with [[RegisteredClass alloc] init].

Or you can register class with custom creating block:

ZIKAnyViewRouter.register(RoutableView<EditorViewInput>(), 
                 forMakingView: EditorViewController.self) { (config, router) -> EditorViewInput? in
                     EditorViewController *destination = ... // instantiate your view controller
                     return destination;
        }
Objective-C Sample
[ZIKViewRouter
    registerViewProtocol:ZIKRoutable(EditorViewInput)
    forMakingView:[EditorViewController class]
    making:^id _Nullable(ZIKViewRouteConfiguration *config, ZIKViewRouter *router) {
        EditorViewController *destination = ... // instantiate your view controller
        return destination;
 }];

or with custom factory function:

function makeEditorViewController(config: ViewRouteConfig) -> EditorViewInput? {
    NoteEditorViewController *destination = ... // instantiate your view controller
    return destination;
}

ZIKAnyViewRouter.register(RoutableView<EditorViewInput>(), 
                 forMakingView: NoteEditorViewController.self, making: makeEditorViewController)
Objective-C Sample
id<EditorViewInput> makeEditorViewController(ZIKViewRouteConfiguration *config) {
    NoteEditorViewController *destination = ... // instantiate your view controller
    return destination;
}

[ZIKViewRouter
    registerViewProtocol:ZIKRoutable(EditorViewInput)
    forMakingView:[NoteEditorViewController class]
    factory:makeEditorViewController];

or with much more complex blocks:

ZIKViewRoute<EditorViewController, ViewRouteConfig>
    .make(withDestination: EditorViewController.self,
          makeDestination: { (config, router) -> EditorViewController? in
            return EditorViewController()
    })
    .register(RoutableView<EditorViewInput>())
Objective-C Sample
[ZIKViewRoute<EditorViewController *, ZIKViewRouteConfig *> 
	makeRouteWithDestination:[EditorViewController class] 
	makeDestination:^ EditorViewController * _Nullable(ZIKViewRouteConfig * _Nonnull config, __kindof ZIKRouter<EditorViewController *,ZIKViewRouteConfig *,ZIKViewRemoveConfiguration *> * _Nonnull router) {
        return [[EditorViewController alloc] init];
    }];

Next section: Module Registration