iOS?Lotusoot模塊化工具應(yīng)用的動態(tài)思路
下文,寫的是 Swift 依賴
OC 庫,沒有命名空間
組件化的要點(diǎn)-約定
個人覺得
例如,URL 路由的注冊,就是把約定的信息,傳過去。作為服務(wù)。
Lotusoot 包含服務(wù)調(diào)用,短鏈的注冊與調(diào)用
下面著重講服務(wù)調(diào)用,短鏈略
場景
project 有兩個依賴 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 編譯時的靜態(tài)特性
協(xié)議的方法,編譯時確定了
需要幾個參數(shù),啥類型的,一般都可以顯式使用
不用看到一個參數(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 方法 ( 這是個約定 )
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 腳本注冊,編譯的時候拿到信息 協(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)翻閱每一個 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')
// 每一個文件
for f in files:
// 每一個 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)… 還有好多,
邏輯是獲取配置,寫入一個 plist
運(yùn)行的時候,啟動
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)
動態(tài)思路
進(jìn)入動態(tài)思路, 動態(tài)地注冊 KV ( 協(xié)議名: 服務(wù)庫名.類名)
上文有一個印象,知道場景,即可
寫文,當(dāng)寫長,
怎樣體現(xiàn)我,10 年工作經(jīng)驗?
上文沒有,堅持湊字?jǐn)?shù)
1,project 拿到 key (協(xié)議名) ,可以的
2,project 拿到所有的依賴信息
通過 MachO 可以
3,project 拿到服務(wù)類的名稱
確保 module B 的類名 = key ( 協(xié)議 ) + Cls
MachO 拿到所有依賴庫的名稱, 每一個 + “.” + key ( 協(xié)議 ) + Cls= MachO 拿到所有依賴庫的名稱, 每一個 + “.” + module B 的類名
然后,看能不能實(shí)例化,
能夠?qū)嵗?,?OK
試了一圈,不能夠?qū)嵗?,就報錯
可能依賴 B, 沒有添加
可能依賴 B 的類名,寫錯了
project 拿到服務(wù)類的名稱, 優(yōu)雅的
確保 module B 的類名 = key ( 協(xié)議 ) + Cls,
硬編碼,是不好的
依賴 A ( 放協(xié)議的 ), 添加一個協(xié)議
public protocol Maid{
var name: String{ get }
}module B 里面,必須有一個叫 key (協(xié)議) + C 的類
該類,遵守 Maid 協(xié)議。
通過協(xié)議屬性,返回 B 中服務(wù)類的名稱
class AccountLotusC: NSObject, Maid{
var name: String{
return String(reflecting: AccountLotusoot.self)
}
}這個過程,與上文模塊化利用協(xié)議的設(shè)計,比較一致
約定是,實(shí)現(xiàn)協(xié)議的服務(wù)模塊,
一定有一個 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、包名+類名的驗證
@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)是,一個 module 一個服務(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)用的動態(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)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下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-02
iOS WebSocket長鏈接的實(shí)現(xiàn)方法
WebSocket是HTML5一種新的協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,本篇文章介紹了iOS WebSocket長鏈接的使用,有一定的參考價值,感興趣的小伙伴們可以參考一下2018-11-11
iOS 修改alertViewController彈框的字體顏色及字體的方法
下面小編就為大家分享一篇iOS 修改alertViewController彈框的字體顏色及字體的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
IOS開發(fā)Swift?與?OC相互調(diào)用詳解
這篇文章主要為大家介紹了IOS開發(fā)Swift?與?OC相互調(diào)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

