一般比较大的项目都会使用到模块化的方式来管理各个组件, 这样每个模块的owner只需要专注于该模块的开发,而不需要关心其他模块. 于是本文简单介绍一下Swift模块化框架的简单实现.
模块化实现
整体思路是这样的, app启动后先初始化一个模块管理类ModuleManager, 然后由ModuleManager去初始化各个模块. 可以参考下面的结构图
App 启动之后调用ModuleManager的 applicationDidFinishLaunching等方法, 然后ModuleManager 负责调用每个模块的applicationDidFinishLaunching等方法.
不分实现的代码如下:
- 先定义所有模块都必须遵循的协议 ModuleProtocol , ModuleProtocol是继承自UIApplicationDelegate
- 然后根据模块的名字注册该模块,比如这个地方是注册"ModuleA.ModuleClassA" (注意swift里是根据 "#模块名.#类名" 的形式来找到该类)
- 然后在 applicationDidFinishLaunching 方法中遍历, 从而调用所有已注册模块的applicationDidFinishLaunching方法
@objc public protocol ModuleProtocol:UIApplicationDelegate { static func create() -> ModuleProtocol? }
func registerModule(_ moduleName:String){ guard let moduleClass:AnyClass = NSClassFromString(moduleName) else{return} var moduleContext:ModuleContext = ModuleContext() moduleContext.moduleClass = moduleClass moduleContext.moduleName = NSStringFromClass(moduleClass) guard let moduleObject:ModuleProtocol = (moduleContext.moduleClass as! ModuleProtocol.Type).create() else { return } moduleContext.modueleObject = moduleObject moduleContextArray.append(moduleContext) }
public func applicationDidFinishLaunching(_ application: UIApplication) { for context in moduleContextArray { if (context.modueleObject?.responds(to: #selector(applicationDidFinishLaunching(_:))))!{ context.modueleObject?.applicationDidFinishLaunching?(application) } } }
模块之间的解藕
开发过程中经常会遇到这样的情况, 模块A 需要调用 模块B的方法, 模块B 需要调用 模块C 的方法, 而模块C 又调用了 模块A 的方法. 从而导致循环依赖.
为了解决这样的问题, 就需要对各个模块进行解藕. 具体思路是这样的: 对于每一个需要被外部调用的模块(比如ModuleA), 我们会抽离出来一个独立的service模块 ModuleAService 以供给外部模块的调用. 这样ModuleB 只需要依赖 ModuleAService 而不需要依赖 ModuleA, 从而完成解藕
下面是部分实现代码:
- 首先定义一个所有Service模块都必须遵循的协议ServiceProtocol
- 然后注册所有的Service模块, 比如"ModuleAService.ModuleAService"
- 在ModuleB中就可以获取 ModuleAService 协议的实例, 并调用该协议的方法 majorFunctionInModuleA. 由于ModuleA是遵循ModuleAService协议的, 并且已经实现了协议方法majorFunctionInModuleA,所以最终达到了在ModuleB中不引入ModuleA就调用ModuleA的方法的目的.
@objc public protocol ServiceProtocol{ }
func registerService(_ serviceName:String){ guard let serviceClass:AnyClass = NSClassFromString(serviceName) else{ return } var count:UInt32 = 0 guard let protocolList = class_copyProtocolList(serviceClass, &count) else{ return } var serviceProtocolList:[Protocol] = [] for i in 0..<count { let foundServiceProtocols = findServiceProtocols(protocolList[Int(i)]) serviceProtocolList.append(contentsOf: foundServiceProtocols) } for serviceProtocol in serviceProtocolList { setServiceClass(serviceClass, forProtocol: serviceProtocol) } }
let instanceList:[ModuleAService] = ModuleManager.sharedInstance.servicesForProtocol(ModuleAService.self) as! [ModuleAService] let instance:ModuleAService = instanceList.first! instance.majorFunctionInModuleA()
public class ModuleAServiceClass: NSObject,ModuleAService { public func majorFunctionInModuleA() { let moduleA = ModuleClassA() moduleA.majorFunctionInModuleA() } }