ZRouter 1.1.1

ZRouter 1.1.1

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布时间最新发布2019年8月
SPM支持 SPM

zuik 维护。



ZRouter 1.1.1

  • Zuikyo

ZIKRouter

ZIKRouter Carthage compatible license

面向接口的模块管理器,通过协议进行依赖注入。

视图路由器可以通过一个方法执行 UIKit/AppKit 中的所有导航类型。

服务路由器可以找到并准备与其协议相对应的模块。


这是一个用于模块间解耦合和通信,基于接口进行模块管理和依赖注入的组件化路由工具。用多种方式最大限度地发挥编译检查的功能。

通过 protocol 寻找对应的模块,并用 protocol 进行依赖注入和模块通信。

服务路由器可以管理任意自定义模块。视图路由器进一步封装了界面跳转。

中文文档


特性

  • Swift 和 Objective-C 支持
  • iOS, macOS 和 tvOS 支持
  • 为快速创建路由器提供的文件模板
  • 为 UIViewController/NSViewController, UIView/NSView 和任意类提供路由
  • 依赖注入,包括动态注入和静态注入
  • 声明路由协议进行编译时检查。使用未声明的协议会导致编译错误。这是最有力的特性之一
  • 与其协议匹配模块
  • 支持 URL 路由
  • 通过其协议而不是参数字典来配置模块
  • 所需协议和提供协议以进行彻底解耦合
  • 解耦合模块的适配器以增加兼容接口
  • 故事板支持。segue的可视视图可以自动准备
  • 为UIKit / AppKit中的所有转场方法和解绑方法进行封装,以及自定义转场
  • 对视图转场进行错误检查
  • 视图转场使用AOP
  • 内存泄漏检测
  • 自定义事件处理
  • 自动注册
  • 高度可扩展

快速入门指南

  1. 创建路由器
    1. 路由器子类
    2. 简单路由器
  2. 声明路由类型
  3. 视图路由器
    1. 直接转场
    2. 转场前准备
    3. 创建目的地
    4. 必需参数和特殊参数
    5. 在目的地执行
    6. 在目的地准备
    7. 删除
    8. 适配器
    9. 模块化
    10. URL路由器
    11. 其他功能
  4. 服务路由器
  5. 演示和实践
  6. 文件模板

文档

设计理念

设计理念

基础

  1. 路由器实现
  2. 模块注册
  3. 路由声明
  4. 类型检查
  5. 执行路由
  6. 删除路由
  7. 使用自定义配置传输参数

高级功能

  1. 错误处理
  2. 故事板和自动创建
  3. AOP
  4. 依赖注入
  5. 循环依赖
  6. 模块适配器
  7. 单元测试

常见问题解答

需求

  • iOS 7.0+
  • Swift 3.2+
  • Xcode 9.0+

安装

CocoaPods

将此行添加到您的 Podfile。

对于 Objective-C 项目

pod 'ZIKRouter', '>= 1.1.1'

# or only use ServiceRouter
pod 'ZIKRouter/ServiceRouter' , '>=1.1.1'

对于 Swift 项目

pod 'ZRouter', '>= 1.1.1'

# or only use ServiceRouter
pod 'ZRouter/ServiceRouter' , '>=1.1.1'

Carthage

将此行添加到您的 Cartfile

github "Zuikyo/ZIKRouter" >= 1.1.1

构建框架

carthage update

构建 DEBUG 版本以启用路由检查

carthage update --configuration Debug

记住在生产环境中使用 RELEASE 版本。

对于 Objective-C 项目,使用 ZIKRouter.framework。对于 Swift 项目,使用 ZRouter.framework

入门

这是示例视图控制器和协议:

///Editor view's interface
protocol EditorViewInput: class {
    weak var delegate: EditorDelegate? { get set }
    func constructForCreatingNewNote()
}

///Editor view controller
class NoteEditorViewController: UIViewController, EditorViewInput {
    ...
}
Objective-C 示例
///editor view's interface
@protocol EditorViewInput <ZIKViewRoutable>
@property (nonatomic, weak) id<EditorDelegate> delegate;
- (void)constructForCreatingNewNote;
@end
///Editor view controller
@interface NoteEditorViewController: UIViewController <EditorViewInput>
@end
@implementation NoteEditorViewController
@end

创建模块路由的步骤有两个。

1. 创建路由器

为了让您的类成为模块化,您需要为模块创建一个路由器。您不需要修改模块的代码。这将减少对现有模块重构的成本。

1.1 路由子类

为您的模块创建路由子类

import ZIKRouter.Internal
import ZRouter

class NoteEditorViewRouter: ZIKViewRouter<NoteEditorViewController, ViewRouteConfig> {
    override class func registerRoutableDestination() {
        // Register class with this router. A router can register multi views, and a view can be registered with multi routers
        registerView(NoteEditorViewController.self)
        // Register protocol. Then we can fetch this router with the protocol
        register(RoutableView<EditorViewInput>())
    }
    
    // Return the destination module
    override func destination(with configuration: ViewRouteConfig) -> NoteEditorViewController? {
        // In configuration, you can get parameters from the caller for creating the instance
        let destination: NoteEditorViewController? = ... /// instantiate your view controller
        return destination
    }
    
    override func prepareDestination(_ destination: NoteEditorViewController, configuration: ViewRouteConfig) {
        // Inject dependencies to destination
    }
}
Objective-C 示例
//NoteEditorViewRouter.h
@import ZIKRouter;

@interface NoteEditorViewRouter : ZIKViewRouter
@end

//NoteEditorViewRouter.m
@import ZIKRouter.Internal;

@implementation NoteEditorViewRouter

+ (void)registerRoutableDestination {
    // Register class with this router. A router can register multi views, and a view can be registered with multi routers
    [self registerView:[NoteEditorViewController class]];
    // Register protocol. Then we can fetch this router with the protocol
    [self registerViewProtocol:ZIKRoutable(EditorViewInput)];
}

// Return the destination module
- (NoteEditorViewController *)destinationWithConfiguration:(ZIKViewRouteConfiguration *)configuration {
    // In configuration, you can get parameters from the caller for creating the instance 
    NoteEditorViewController *destination = ... // instantiate your view controller
    return destination;
}

- (void)prepareDestination:(NoteEditorViewController *)destination configuration:(ZIKViewRouteConfiguration *)configuration {
    // Inject dependencies to destination
}

@end

每个路由可以控制自己的路由,例如使用不同的自定义过渡。路由可以很容易地添加额外功能。

阅读文档以获取更多信息以及更多可覆盖的方法。

1.2 简单路由

如果您的模块非常简单且不需要路由子类,您只需以更简单的方式注册类

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

或将自定义创建块

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

或使用自定义工厂函数

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

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

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

2. 声明可路由类型

该声明用于编译时检查路由,并支持故事板。

// Declare NoteEditorViewController is routable
// This means there is a router for NoteEditorViewController
extension NoteEditorViewController: ZIKRoutableView {
}

// Declare EditorViewInput is routable
// This means you can use EditorViewInput to fetch router
extension RoutableView where Protocol == EditorViewInput {
    init() { self.init(declaredProtocol: Protocol.self) }
}
Objective-C 示例
// Declare NoteEditorViewController is routable
// This means there is a router for NoteEditorViewController
DeclareRoutableView(NoteEditorViewController, NoteEditorViewRouter)

// If the protocol inherits from ZIKViewRoutable, it's routable
// This means you can use EditorViewInput to fetch router
@protocol EditorViewInput <ZIKViewRoutable>
@property (nonatomic, weak) id<EditorDelegate> delegate;
- (void)constructForCreatingNewNote;
@end

如果您使用未声明的协议进行路由,将会出现编译时错误。因此,管理协议和了解哪些协议是可路由的既安全又容易。

Swift 中的不可路由错误

Unroutable-error-Swift

Objective-C 中的不可路由错误

Unroutable-error-OC

现在您可以通过路由获取并显示 NoteEditorViewController

视图路由器

直接过渡

直接过渡到编辑视图

class TestViewController: UIViewController {

    // Transition to editor view directly
    func showEditorDirectly() {
        Router.perform(to: RoutableView<EditorViewInput>(), path: .push(from: self))
    }
}
Objective-C 示例
@implementation TestViewController

- (void)showEditorDirectly {
    // Transition to editor view directly
    [ZIKRouterToView(EditorViewInput) performPath:ZIKViewRoutePath.pushFrom(self)];
}

@end

您可以使用 ViewRoutePath 改变过渡类型

enum ViewRoutePath {
    case push(from: UIViewController)
    case presentModally(from: UIViewController)
    case presentAsPopover(from: UIViewController, configure: ZIKViewRoutePopoverConfigure)
    case performSegue(from: UIViewController, identifier: String, sender: Any?)
    case show(from: UIViewController)
    case showDetail(from: UIViewController)
    case addAsChildViewController(from: UIViewController, addingChildViewHandler: (UIViewController, @escaping () -> Void) -> Void)
    case addAsSubview(from: UIView)
    case custom(from: ZIKViewRouteSource?)
    case makeDestination
    case extensible(path: ZIKViewRoutePath)
}

封装视图过渡可以隐藏 UIKit 的细节,然后您可以在视图层外部(呈现器、视图模型、交互器、服务)执行路由,并实现跨平台。

过渡前的准备

在过渡到编辑视图之前进行准备

class TestViewController: UIViewController {

    // Transition to editor view, and prepare the destination with EditorViewInput
    func showEditor() {
        Router.perform(
            to: RoutableView<EditorViewInput>(),
            path: .push(from: self),
            configuring: { (config, _) in
                // Route config
                // Prepare the destination before transition
                config.prepareDestination = { [weak self] destination in
                    //destination is inferred as EditorViewInput
                    destination.delegate = self
                    destination.constructForCreatingNewNote()
                }
                config.successHandler = { destination in
                    // Transition succeed
                }
                config.errorHandler = { (action, error) in
                    // Transition failed
                }                
        })
    }
}
Objective-C 示例
@implementation TestViewController

- (void)showEditor {
    // Transition to editor view, and prepare the destination with EditorViewInput
    [ZIKRouterToView(EditorViewInput)
	     performPath:ZIKViewRoutePath.pushFrom(self)
	     configuring:^(ZIKViewRouteConfig *config) {
	         // Route config
	         // Prepare the destination before transition
	         config.prepareDestination = ^(id<EditorViewInput> destination) {
	             destination.delegate = self;
	             [destination constructForCreatingNewNote];
	         };
	         config.successHandler = ^(id<EditorViewInput> destination) {
	             // Transition is completed
	         };
	         config.errorHandler = ^(ZIKRouteAction routeAction, NSError * error) {
	             // Transition failed
	         };
	     }];
}

@end

了解更多详情,请阅读执行路由.

创建目标

如果您不想显示视图,但只需要模块的实例,您可以使用makeDestination

// destination is inferred as EditorViewInput
let destination = Router.makeDestination(to: RoutableView<EditorViewInput>())
Objective-C 示例
id<EditorViewInput> destination = [ZIKRouterToView(EditorViewInput) makeDestination];

必需参数和特殊参数

一些参数无法通过目标协议传递

  • 目标类使用自定义初始化器来创建实例,路由器需要从调用者获取必需参数

  • 该模块包含多个组件,您需要将这些参数传递给这些组件。这些参数不属于目标,因此不应存在于目标的协议中

您可以使用模块配置协议和自定义配置来传递参数。

我们使用另一个可路由协议EditorViewModuleInput作为配置协议进行路由,而不是EditorViewInput

// In general, a module config protocol only contains `makeDestinationWith`, for declaring parameters and destination type. You can also add other properties or methods
protocol EditorViewModuleInput: class {
    // Factory method for transferring parameters and making destination
    var makeDestinationWith: (_ note: Note) -> EditorViewInput? { get }
}
Objective-C 示例
// In general, a module config protocol only contains `makeDestinationWith`, for declaring parameters and destination type. You can also add other properties or methods
@protocol EditorViewModuleInput <ZIKViewModuleRoutable>
 // Factory method for transferring parameters and making destination
@property (nonatomic, copy, readonly) id<EditorViewInput> _Nullable(^makeDestinationWith)(Note *note);
@end

此配置与具有EditorViewModuleInput协议的目标类似工厂。它声明了用于创建目标的参数

现在用户可以使用其模块配置协议及其参数进行传递

var note = ...
Router.makeDestination(to: RoutableViewModule<EditorViewModuleInput>()) { (config) in
     // Transfer parameters and get EditorViewInput
     let destination = config.makeDestinationWith(note)
}
Objective-C 示例
Note *note = ...
[ZIKRouterToViewModule(EditorViewModuleInput)
    performPath:ZIKViewRoutePath.showFrom(self)
    configuring:^(ZIKViewRouteConfiguration<EditorViewModuleInput> *config) {
        // Transfer parameters and get EditorViewInput
        id<EditorViewInput> destination = config.makeDestinationWith(note);
 }];

了解更多详情,请阅读使用自定义配置传递参数.

在目标上执行

如果您从其他地方获取目标,可以使用其路由器在目标上执行操作。

例如,一个UIViewController支持3D触控,并实现了UIViewControllerPreviewingDelegate

class SourceViewController: UIViewController, UIViewControllerPreviewingDelegate {
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        // Return the destination UIViewController to let system preview it
        let destination = Router.makeDestination(to: RoutableView<EditorViewInput>())
        return destination
    }
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        guard let destination = viewControllerToCommit as? EditorViewInput else {
            return
        }
        // Show the destination
        Router.to(RoutableView<EditorViewInput>())?.perform(onDestination: destination, path: .presentModally(from: self))
}
Objective-C 示例
@implementation SourceViewController

- (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {
    //Return the destination UIViewController to let system preview it
    UIViewController<EditorViewInput> *destination = [ZIKRouterToView(EditorViewInput) makeDestination];
    return destination;
}

- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
    // Show the destination
    UIViewController<EditorViewInput> *destination;
    if ([viewControllerToCommit conformsToProtocol:@protocol(EditorViewInput)]) {
        destination = viewControllerToCommit;
    } else {
        return;
    }
    [ZIKRouterToView(EditorViewInput) performOnDestination:destination path:ZIKViewRoutePath.presentModallyFrom(self)];
}

@end

在目的地准备

如果您不想显示目的地,只想准备现有目的地,您可以使用其路由器来准备目的地。

如果路由器在其内部注入依赖项,这可以正确设置目的地实例。

var destination: DestinationViewInput = ...
Router.to(RoutableView<EditorViewInput>())?.prepare(destination: destination, configuring: { (config, _) in
            config.prepareDestination = { destination in
                // Prepare
            }
        })
Objective-C 示例
UIViewController<EditorViewInput> *destination = ...
[ZIKRouterToView(EditorViewInput) prepareDestination:destination configuring:^(ZIKViewRouteConfiguration *config) {
            config.prepareDestination = ^(id<EditorViewInput> destination) {
                // Prepare
            };
        }];

删除

您可以通过removeRoute删除视图,而不需要使用弹出/消失/从父视图控制器中移除/从视图中移除。

class TestViewController: UIViewController {
    var router: DestinationViewRouter<EditorViewInput>?
    
    func showEditor() {
        // Hold the router
        router = Router.perform(to: RoutableView<EditorViewInput>(), path: .push(from: self))
    }
    
    // Router will pop the editor view controller
    func removeEditorDirectly() {
        guard let router = router, router.canRemove else {
            return
        }
        router.removeRoute()
        router = nil
    }
    
    func removeEditorWithResult() {
        guard let router = router, router.canRemove else {
            return
        }
        router.removeRoute(successHandler: {
            print("remove success")
        }, errorHandler: { (action, error) in
            print("remove failed, error: \(error)")
        })
        router = nil
    }
    
    func removeEditorAndPrepare() {
        guard let router = router, router.canRemove else {
            return
        }
        router.removeRoute(configuring: { (config) in
            config.animated = true
            config.prepareDestination = { destination in
                // Use destination before remove it
            }
        })
        router = nil
    }
}
Objective-C 示例
@interface TestViewController()
@property (nonatomic, strong) ZIKDestinationViewRouter(id<EditorViewInput>) *router;
@end
@implementation TestViewController

- (void)showEditorDirectly {
    // Hold the router
    self.router = [ZIKRouterToView(EditorViewInput) performPath:ZIKViewRoutePath.pushFrom(self)];
}

// Router will pop the editor view controller
- (void)removeEditorDirectly {
    if (![self.router canRemove]) {
        return;
    }
    [self.router removeRoute];
    self.router = nil;
}

- (void)removeEditorWithResult {
    if (![self.router canRemove]) {
        return;
    }
    [self.router removeRouteWithSuccessHandler:^{
        NSLog(@"pop success");
    } errorHandler:^(ZIKRouteAction routeAction, NSError *error) {
        NSLog(@"pop failed,error: %@",error);
    }];
    self.router = nil;
}

- (void)removeEditorAndPrepare {
    if (![self.router canRemove]) {
        return;
    }
    [self.router removeRouteWithConfiguring:^(ZIKViewRemoveConfiguration *config) {
        config.animated = YES;
        config.prepareDestination = ^(UIViewController<EditorViewInput> *destination) {
            // Use destination before remove it
        };
    }];
    self.router = nil;
}

@end

更多详细信息,请阅读删除路由

适配器

只要协议提供了与实际协议相同的接口,您就可以使用另一个协议来获取路由器。即使协议与实际协议略微不同,您也可以通过分类、扩展和代理将两个协议适配。

用户使用的协议要求

/// Required protocol to use editor module
protocol RequiredEditorViewInput: class {
    weak var delegate: EditorDelegate? { get set }
    func constructForCreatingNewNote()
}
Objective-C 示例
/// Required protocol to use editor module
@protocol RequiredEditorViewInput <ZIKViewRoutable>
@property (nonatomic, weak) id<EditorDelegate> delegate;
- (void)constructForCreatingNewNote;
@end

在主应用程序上下文中,连接所需的协议和提供协议

/// In the host app, add required protocol to editor router
class EditorViewAdapter: ZIKViewRouteAdapter {
    override class func registerRoutableDestination() {
        // If you can get the router, you can just register RequiredEditorViewInput to it
        NoteEditorViewRouter.register(RoutableView<RequiredEditorViewInput>())
        
        // If you don't know the router, you can use adapter
        register(adapter: RoutableView<RequiredEditorViewInput>(), forAdaptee: RoutableView<EditorViewInput>())
    }
}

/// Make NoteEditorViewController conform to RequiredEditorViewInput
extension NoteEditorViewController: RequiredEditorViewInput {
}
Objective-C 示例
/// In the host app, add required protocol to editor router

//EditorViewAdapter.h
@interface EditorViewAdapter : ZIKViewRouteAdapter
@end

//EditorViewAdapter.m
@implementation EditorViewAdapter

+ (void)registerRoutableDestination {
	// If you can get the router, you can just register RequiredEditorViewInput to it
	[NoteEditorViewRouter registerViewProtocol:ZIKRoutable(RequiredEditorViewInput)];
	// If you don't know the router, you can use adapter
	[self registerDestinationAdapter:ZIKRoutable(RequiredEditorViewInput) forAdaptee:ZIKRoutable(EditorViewInput)];
}

@end

/// Make NoteEditorViewController conform to RequiredEditorViewInput
@interface NoteEditorViewController (Adapter) <RequiredEditorViewInput>
@end
@implementation NoteEditorViewController (Adapter)
@end

适配后,RequiredEditorViewInputEditorViewInput可以使用相同的路由器。

使用RequiredEditorViewInput获取模块

class TestViewController: UIViewController {

    func showEditorDirectly() {
        Router.perform(to: RoutableView<RequiredEditorViewInput>(), path: .push(from: self))
    }
}
Objective-C 示例
@implementation TestViewController

- (void)showEditorDirectly {
    [ZIKRouterToView(RequiredEditorViewInput) performPath:ZIKViewRoutePath.pushFrom(self)];
}

@end

使用required协议provided协议可完全解耦模块,适配界面并声明模块的依赖关系。而且您不需要使用公共头文件来管理这些协议。

模块化

required协议provided协议分离,可以使您的代码真正模块化。调用者声明其required协议,提供的模块可以轻松地替换为具有相同required协议的其他模块。

请阅读示例中的ZIKLoginModule模块。登录模块依赖于警报模块,而警报模块在ZIKRouterDemoZIKRouterDemo-macOS中不同。您可以通过更改提供的模块来修改登录模块,而无需修改登录模块中的任何内容。

更多详细信息,请阅读模块适配器

URL 路由器

ZIKRouter 还提供默认的 URL 路由器。与模块通过 URL 进行通信非常简单。

URL 路由器默认不被包含。如果您要使用它,请将子模块 pod 'ZIKRouter/URLRouter' 添加到您的 Podfile 中,并通过调用 [ZIKRouter enableDefaultURLRouteRule] 来启用 URL 路由器。

您可以使用 URL 注册路由器

class NoteEditorViewRouter: ZIKViewRouter<NoteEditorViewController, ViewRouteConfig> {
    override class func registerRoutableDestination() {
        registerView(NoteEditorViewController.self)
        register(RoutableView<EditorViewInput>())
        // Register url
        registerURLPattern("app://editor/:title")
    }
}
Objective-C 示例
@implementation NoteEditorViewRouter

+ (void)registerRoutableDestination {
    [self registerView:[NoteEditorViewController class]];
    [self registerViewProtocol:ZIKRoutable(EditorViewInput)];
    // Register url
    [self registerURLPattern:@"app://editor/:title"];
}

@end

然后您可以通过它获取路由器

ZIKAnyViewRouter.performURL("app://editor/test_note", path: .push(from: self))
Objective-C 示例
[ZIKAnyViewRouter performURL:@"app://editor/test_note" path:ZIKViewRoutePath.pushFrom(self)];

并处理 URL 方案

public func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    let urlString = url.absoluteString
    if let _ = ZIKAnyViewRouter.performURL(urlString, fromSource: self.rootViewController) {
        return true
    } else if let _ = ZIKAnyServiceRouter.performURL(urlString) {
        return true
    } else {
        return false
    }
}
Objective-C 示例
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([ZIKAnyViewRouter performURL:urlString fromSource:self.rootViewController]) {
        return YES;
    } else if ([ZIKAnyServiceRouter performURL:urlString]) {
        return YES;
    } else {
        return NO;
    }
}

如果您的项目对 URL 路由器有不同的要求,您可以自己编写 URL 路由器。您可以创建自定义的 ZIKRouter 作为父类,在其中添加更多强大的功能。请参阅 ZIKRouter+URLRouter.h

其他功能

还有其他功能,您可以在文档中获取详细信息

服务路由器

除了视图之外,您还可以获取任何服务模块

/// time service's interface
protocol TimeServiceInput {
    func currentTimeString() -> String
}
class TestViewController: UIViewController {
    @IBOutlet weak var timeLabel: UILabel!
    
    func callTimeService() {
        // Get the service for TimeServiceInput
        let timeService = Router.makeDestination(
            to: RoutableService<TimeServiceInput>(),
            preparation: { destination in
            // prepare the service if needed
        })
        //Use the service
        timeLabel.text = timeService.currentTimeString()
    }
}
Objective-C 示例
/// time service's interface
@protocol TimeServiceInput <ZIKServiceRoutable>
- (NSString *)currentTimeString;
@end
@interface TestViewController ()
@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
@end

@implementation TestViewController

- (void)callTimeService {
   // Get the service for TimeServiceInput
   id<TimeServiceInput> timeService = [ZIKRouterToService(TimeServiceInput) makeDestination];
   self.timeLabel.text = [timeService currentTimeString];    
}

示例和实践

ZIKRouter 最初是为 VIPER 架构设计的。但您也可以在 MVC 或其他任何地方使用它。

此存储库中的示例(ZIKRouterDemo)显示了如何使用 ZIKRouter 执行每种路由类型。打开 Router.xcworkspace 运行它。

如果您想看到它在一个 VIPER 架构应用中的工作方式,请转到 ZIKViper

文件模板

您可以使用 Xcode 文件模板来快速创建路由器和协议代码

File Template

模板 ZIKRouter.xctemplateTemplates

ZIKRouter.xctemplate复制到~/Library/Developer/Xcode/Templates/ZIKRouter.xctemplate,然后您可以在Xcode → 文件 →新建 → 文件 → 模板中使用它。

许可证

ZIKRouter在MIT许可证下可用。有关更多信息,请参阅LICENSE文件。