iOS?Lotusoot模塊化工具應(yīng)用的動(dòng)態(tài)思路
下文,寫的是 Swift 依賴
OC 庫,沒有命名空間
組件化的要點(diǎn)-約定
個(gè)人覺得
例如,URL 路由的注冊,就是把約定的信息,傳過去。作為服務(wù)。
Lotusoot 包含服務(wù)調(diào)用,短鏈的注冊與調(diào)用
下面著重講服務(wù)調(diào)用,短鏈略
場景
project 有兩個(gè)依賴 A (協(xié)議) 和 B (協(xié)議的實(shí)現(xiàn)者,提供服務(wù))
project 引用 A,知道了協(xié)議信息
project 不引用 B , project 對 B 一無所知
這樣 project 把 B 去掉,編譯的更快
B 依賴 A, 引用 A, 實(shí)現(xiàn) A 的協(xié)議,提供服務(wù)
調(diào)用服務(wù)
// 拿到 key let lotus = s(AccountLotus.self) // kv 取得提供服務(wù)的實(shí)例 let accountModule: AccountLotus = LotusootCoordinator.lotusoot(lotus: lotus) as! AccountLotus // 調(diào)用服務(wù) accountModule.login(username: "zhoulingyu", password: "wow") { (error) in print(error ?? "1234") }
第 3 步,調(diào)用服務(wù)很簡單
第 2 步,挺精彩,充分使用了 Swift 編譯時(shí)的靜態(tài)特性
協(xié)議的方法,編譯時(shí)確定了
需要幾個(gè)參數(shù),啥類型的,一般都可以顯式使用
不用看到一個(gè)參數(shù)字典,啊,這是啥
// 第 2 步。從下面取 // 鍵值對,值是提供服務(wù)的對象 var lotusootMap: Dictionary = Dictionary<String, Any>()
第 1 步, 拿到鍵
這里把協(xié)議名,作為 key
// 使用泛型,取其描述 // 協(xié)議,轉(zhuǎn)協(xié)議名 public extension String { init<Subject>(_ instance: Subject) { self.init(describing: instance) } } /// 通過 Subject 快速獲取字符串 public func s<Subject>(_ instance: Subject) -> String { return String(instance) }
注冊服務(wù)
1, Project 沒有 import B ( 提供服務(wù) ), 怎么使用 B 的功能?
public static func registerAll(serviceMap: Dictionary<String, String>) { for (lotus, lotusootName) in serviceMap { // lotus, 協(xié)議名 // lotusootName, 包名.類名 let classStringName = lotusootName // 反射,產(chǎn)生類 // 提供服務(wù)的類,一定是 NSObject 的子類,擁有 init 方法 ( 這是個(gè)約定 ) let classType = NSClassFromString(classStringName) as? NSObject.Type if let type = classType { // 產(chǎn)生對應(yīng)的實(shí)例,強(qiáng)轉(zhuǎn)為遵守協(xié)議的 ,即可 let lotusoot = type.init() register(lotusoot: lotusoot, lotusName: lotus) } } }
2, 這里使用 python 腳本注冊,編譯的時(shí)候拿到信息 協(xié)議名:包名.類名
通過約定, 標(biāo)記
// @NameSpace(ZLYAccountModule) // @Lotusoot(AccountLotusoot) // @Lotus(AccountLotus) class AccountLotusoot: NSObject, AccountLotus {}
python 腳本找出標(biāo)記,整合,放入 plist
文件中
1, 腳本入口
lotusootSuffix = 'Lotusoot' length = len(sys.argv) if length != 3 and length != 4: print 'parameter error' os._exit(1) if length == 4: lotusootSuffix = sys.argv[3] lotusootFiles = findLotusoots(scanPath, lotusootSuffix + '.swift') else: // 走這里 lotusootFiles = findAmbiguityLotusoots(scanPath)
翻閱每一個(gè) swift 文件
def findAmbiguityLotusoots(path): list = [] for root, subFolders, files in os.walk(path): # Ignore 'Target Support Files' and 'Pods.xcodeproj' // 不需要處理的,不處理 if 'Target Support Files' in subFolders: subFolders.remove('Target Support Files') // 不需要處理的,略 if 'Pods.xcodeproj' in subFolders: subFolders.remove('Pods.xcodeproj') // 每一個(gè)文件 for f in files: // 每一個(gè) Swift 文件 if f.endswith('.swift'): // 獲取標(biāo)記的配置 tup = getLotusootConfig(os.path.join(root, f)) if tup[0] and tup[1] and tup[2]: // 三者都滿足,把文件路徑,給添加了 list.append(f) return list
掃描每一行,
獲取配置,上面看到的包名,命名空間
@NameSpace(ZLYAccountModule)
上面看到的類名
@Lotusoot(AccountLotusoot)
上面看到的 key ( 協(xié)議名 )
@Lotus(AccountLotus)
def getLotusootConfig(file): lotus = '' lotusoot = '' namespace = '' // 翻閱,文件的每一行 for line in open(file): // 上面看到的 key if getLotus(line): lotus = getLotus(line) // 上面看到的類名 if getLotusoot(line): lotusoot = getLotusoot(line) // 上面看到的包名,命名空間 if getNameSpace(line): namespace = getNameSpace(line) return (lotus, lotusoot, namespace)
… 還有好多,
邏輯是獲取配置,寫入一個(gè) plist
運(yùn)行的時(shí)候,啟動(dòng)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { LotusootCoordinator.registerAll() return true }
注冊就是,讀取剛才寫入的 plist, 作為 [協(xié)議名 : 包名.類名 ] 的字典,
@objc public static func registerAll() { let lotusPlistPath = Bundle.main.path(forResource: "Lotusoot", ofType: "plist") if let lotusPlistPath = lotusPlistPath { let map = NSDictionary(contentsOfFile: lotusPlistPath) registerAll(serviceMap: map as! Dictionary<String, String>) } }
與上文,相呼應(yīng)
動(dòng)態(tài)思路
進(jìn)入動(dòng)態(tài)思路, 動(dòng)態(tài)地注冊 KV ( 協(xié)議名: 服務(wù)庫名.類名)
上文有一個(gè)印象,知道場景,即可
寫文,當(dāng)寫長,
怎樣體現(xiàn)我,10 年工作經(jīng)驗(yàn)?
上文沒有,堅(jiān)持湊字?jǐn)?shù)
1,project 拿到 key (協(xié)議名) ,可以的
2,project 拿到所有的依賴信息
通過 MachO 可以
3,project 拿到服務(wù)類的名稱
確保 module B 的類名 = key ( 協(xié)議 ) + Cls
MachO
拿到所有依賴庫的名稱, 每一個(gè) + “.” + key ( 協(xié)議 ) + Cls= MachO
拿到所有依賴庫的名稱, 每一個(gè) + “.” + module B 的類名
然后,看能不能實(shí)例化,
能夠?qū)嵗?,?OK
試了一圈,不能夠?qū)嵗?,就?bào)錯(cuò)
可能依賴 B, 沒有添加
可能依賴 B 的類名,寫錯(cuò)了
project 拿到服務(wù)類的名稱, 優(yōu)雅的
確保 module B 的類名 = key ( 協(xié)議 ) + Cls,
硬編碼,是不好的
依賴 A ( 放協(xié)議的 ), 添加一個(gè)協(xié)議
public protocol Maid{ var name: String{ get } }
module B 里面,必須有一個(gè)叫 key (協(xié)議) + C 的類
該類,遵守 Maid
協(xié)議。
通過協(xié)議屬性,返回 B 中服務(wù)類的名稱
class AccountLotusC: NSObject, Maid{ var name: String{ return String(reflecting: AccountLotusoot.self) } }
這個(gè)過程,與上文模塊化利用協(xié)議的設(shè)計(jì),比較一致
約定是,實(shí)現(xiàn)協(xié)議的服務(wù)模塊,
一定有一個(gè) key + C 的類
提供服務(wù)類的名稱
硬編碼,比較輕微
代碼實(shí)現(xiàn)
1、MachO 獲取命名空間
import MachO lazy var moduleNames: [String] = { () -> [String] in // 找到 project 名稱,一會去除 let mainNameTmp = NSStringFromClass(LotusootCoordinator.self) guard let mainName = mainNameTmp.components(separatedBy: ".").first else{ fatalError("emptyMainProject") } var result = [String]() let cnt = _dyld_image_count() // 處理所有的包,系統(tǒng)的,用戶的 for i in 0..<cnt{ if let tmp = _dyld_get_image_name(i){ let name = String(validatingUTF8: tmp) // 系統(tǒng)的,不用管 if let candidate = name, candidate.hasPrefix("/Users"){ if let tmp = candidate.components(separatedBy: "/").last{ // 去除 project 的 if tmp != mainName{ // 拿到用戶依賴 result.append(tmp) } } } } } return result }()
以上,模擬器 OK, 真機(jī)沒試過 ( 手頭沒開發(fā)證書 )
2、包名+類名的驗(yàn)證
@objc public static func lotusoot(lotus: String) -> Any? { // 已經(jīng)緩存了 if let val = sharedInstance.lotusootMap[lotus]{ return val } else{ var i = 0 let names = LotusootCoordinator.sharedInstance.moduleNames let cnt = names.count // 遍歷,用戶包 while i < cnt{ // 按照約定,嘗試制造助手類 let classType = NSClassFromString(names[i] + "." + lotus + "C") as? NSObject.Type if let type = classType { // 實(shí)例化,助手類 let assist = type.init() if let maid = assist as? Maid{ // 拿到 module B 的服務(wù)類的名稱 let classType = NSClassFromString(maid.name) as? NSObject.Type if let type = classType { // 將 module B 的服務(wù)類,實(shí)例化 let lotusoot = type.init() register(lotusoot: lotusoot, lotusName: lotus) } // 默認(rèn)是,一個(gè) module 一個(gè)服務(wù)類, // 排除掉,使用過的用戶類 LotusootCoordinator.sharedInstance.moduleNames.remove(at: i) break } } i+=1 } if let val = sharedInstance.lotusootMap[lotus]{ return val } else{ fatalError("name Module of" + lotus) } } }
到此這篇關(guān)于iOS Lotusoot模塊化工具應(yīng)用的動(dòng)態(tài)思路的文章就介紹到這了,更多相關(guān)iOS Lotusoot模塊化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS簡單登錄LoginViewController、注冊RegisterViewController等功能實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了iOS簡單登錄LoginViewController、注冊RegisterViewController、UcenterViewController功能實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09以代碼實(shí)例總結(jié)iOS應(yīng)用開發(fā)中數(shù)據(jù)的存儲方式
這篇文章主要介紹了iOS應(yīng)用開發(fā)中數(shù)據(jù)的存儲方式的實(shí)例總結(jié),代碼為傳統(tǒng)的Objective-C語言,需要的朋友可以參考下2016-02-02iOS WebSocket長鏈接的實(shí)現(xiàn)方法
WebSocket是HTML5一種新的協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,本篇文章介紹了iOS WebSocket長鏈接的使用,有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11iOS 修改alertViewController彈框的字體顏色及字體的方法
下面小編就為大家分享一篇iOS 修改alertViewController彈框的字體顏色及字體的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01IOS開發(fā)Swift?與?OC相互調(diào)用詳解
這篇文章主要為大家介紹了IOS開發(fā)Swift?與?OC相互調(diào)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08