一般比較大的項目都會使用到模塊化的方式來管理各個組件, 這樣每個模塊的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() } }