iOS?Lotusoot模塊化工具應(yīng)用的動(dòng)態(tài)思路
下文,寫(xiě)的是 Swift 依賴
OC 庫(kù),沒(méi)有命名空間
組件化的要點(diǎn)-約定
個(gè)人覺(jué)得
例如,URL 路由的注冊(cè),就是把約定的信息,傳過(guò)去。作為服務(wù)。
Lotusoot 包含服務(wù)調(diào)用,短鏈的注冊(cè)與調(diào)用
下面著重講服務(wù)調(diào)用,短鏈略
場(chǎng)景
project 有兩個(gè)依賴 A (協(xié)議) 和 B (協(xié)議的實(shí)現(xiàn)者,提供服務(wù))
project 引用 A,知道了協(xié)議信息
project 不引用 B , project 對(duì) B 一無(wú)所知
這樣 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ù)很簡(jiǎn)單
第 2 步,挺精彩,充分使用了 Swift 編譯時(shí)的靜態(tài)特性
協(xié)議的方法,編譯時(shí)確定了
需要幾個(gè)參數(shù),啥類(lèi)型的,一般都可以顯式使用
不用看到一個(gè)參數(shù)字典,啊,這是啥
// 第 2 步。從下面取 // 鍵值對(duì),值是提供服務(wù)的對(duì)象 var lotusootMap: Dictionary = Dictionary<String, Any>()
第 1 步, 拿到鍵
這里把協(xié)議名,作為 key
// 使用泛型,取其描述
// 協(xié)議,轉(zhuǎn)協(xié)議名
public extension String {
init<Subject>(_ instance: Subject) {
self.init(describing: instance)
}
}
/// 通過(guò) Subject 快速獲取字符串
public func s<Subject>(_ instance: Subject) -> String {
return String(instance)
}注冊(cè)服務(wù)
1, Project 沒(méi)有 import B ( 提供服務(wù) ), 怎么使用 B 的功能?
public static func registerAll(serviceMap: Dictionary<String, String>) {
for (lotus, lotusootName) in serviceMap {
// lotus, 協(xié)議名
// lotusootName, 包名.類(lèi)名
let classStringName = lotusootName
// 反射,產(chǎn)生類(lèi)
// 提供服務(wù)的類(lèi),一定是 NSObject 的子類(lèi),擁有 init 方法 ( 這是個(gè)約定 )
let classType = NSClassFromString(classStringName) as? NSObject.Type
if let type = classType {
// 產(chǎn)生對(duì)應(yīng)的實(shí)例,強(qiáng)轉(zhuǎn)為遵守協(xié)議的 ,即可
let lotusoot = type.init()
register(lotusoot: lotusoot, lotusName: lotus)
}
}
}2, 這里使用 python 腳本注冊(cè),編譯的時(shí)候拿到信息 協(xié)議名:包名.類(lèi)名
通過(guò)約定, 標(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)
上面看到的類(lèi)名
@Lotusoot(AccountLotusoot)
上面看到的 key ( 協(xié)議名 )
@Lotus(AccountLotus)
def getLotusootConfig(file):
lotus = ''
lotusoot = ''
namespace = ''
// 翻閱,文件的每一行
for line in open(file):
// 上面看到的 key
if getLotus(line):
lotus = getLotus(line)
// 上面看到的類(lèi)名
if getLotusoot(line):
lotusoot = getLotusoot(line)
// 上面看到的包名,命名空間
if getNameSpace(line):
namespace = getNameSpace(line)
return (lotus, lotusoot, namespace)… 還有好多,
邏輯是獲取配置,寫(xiě)入一個(gè) plist
運(yùn)行的時(shí)候,啟動(dòng)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
LotusootCoordinator.registerAll()
return true
}注冊(cè)就是,讀取剛才寫(xiě)入的 plist, 作為 [協(xié)議名 : 包名.類(lèi)名 ] 的字典,
@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)地注冊(cè) KV ( 協(xié)議名: 服務(wù)庫(kù)名.類(lèi)名)
上文有一個(gè)印象,知道場(chǎng)景,即可
寫(xiě)文,當(dāng)寫(xiě)長(zhǎng),
怎樣體現(xiàn)我,10 年工作經(jīng)驗(yàn)?
上文沒(méi)有,堅(jiān)持湊字?jǐn)?shù)
1,project 拿到 key (協(xié)議名) ,可以的
2,project 拿到所有的依賴信息
通過(guò) MachO 可以
3,project 拿到服務(wù)類(lèi)的名稱
確保 module B 的類(lèi)名 = key ( 協(xié)議 ) + Cls
MachO 拿到所有依賴庫(kù)的名稱, 每一個(gè) + “.” + key ( 協(xié)議 ) + Cls= MachO 拿到所有依賴庫(kù)的名稱, 每一個(gè) + “.” + module B 的類(lèi)名
然后,看能不能實(shí)例化,
能夠?qū)嵗?,?OK
試了一圈,不能夠?qū)嵗蛨?bào)錯(cuò)
可能依賴 B, 沒(méi)有添加
可能依賴 B 的類(lèi)名,寫(xiě)錯(cuò)了
project 拿到服務(wù)類(lèi)的名稱, 優(yōu)雅的
確保 module B 的類(lèi)名 = key ( 協(xié)議 ) + Cls,
硬編碼,是不好的
依賴 A ( 放協(xié)議的 ), 添加一個(gè)協(xié)議
public protocol Maid{
var name: String{ get }
}module B 里面,必須有一個(gè)叫 key (協(xié)議) + C 的類(lèi)
該類(lèi),遵守 Maid 協(xié)議。
通過(guò)協(xié)議屬性,返回 B 中服務(wù)類(lèi)的名稱
class AccountLotusC: NSObject, Maid{
var name: String{
return String(reflecting: AccountLotusoot.self)
}
}這個(gè)過(guò)程,與上文模塊化利用協(xié)議的設(shè)計(jì),比較一致
約定是,實(shí)現(xiàn)協(xié)議的服務(wù)模塊,
一定有一個(gè) key + C 的類(lèi)
提供服務(wù)類(lèi)的名稱
硬編碼,比較輕微
代碼實(shí)現(xiàn)
1、MachO 獲取命名空間
import MachO
lazy var moduleNames: [String] = { () -> [String] in
// 找到 project 名稱,一會(huì)去除
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ī)沒(méi)試過(guò) ( 手頭沒(méi)開(kāi)發(fā)證書(shū) )
2、包名+類(lèi)名的驗(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{
// 按照約定,嘗試制造助手類(lèi)
let classType = NSClassFromString(names[i] + "." + lotus + "C") as? NSObject.Type
if let type = classType {
// 實(shí)例化,助手類(lèi)
let assist = type.init()
if let maid = assist as? Maid{
// 拿到 module B 的服務(wù)類(lèi)的名稱
let classType = NSClassFromString(maid.name) as? NSObject.Type
if let type = classType {
// 將 module B 的服務(wù)類(lèi),實(shí)例化
let lotusoot = type.init()
register(lotusoot: lotusoot, lotusName: lotus)
}
// 默認(rèn)是,一個(gè) module 一個(gè)服務(wù)類(lèi),
// 排除掉,使用過(guò)的用戶類(lèi)
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS?RN啟動(dòng)中管理Native?Module詳解
這篇文章主要為大家介紹了iOS?RN啟動(dòng)中?Native?Module?是如何被管理的,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
iOS內(nèi)存錯(cuò)誤EXC_BAD_ACCESS的解決方法
iOS開(kāi)發(fā),最郁悶的莫過(guò)于程序毫無(wú)征兆地就崩潰了,用bt命令打出調(diào)用棧,給出的是一堆系統(tǒng)EXC_BAD_ACCESS的信息,根本沒(méi)辦法定位問(wèn)題出現(xiàn)在哪里2013-06-06

