以下に、Swiftの依存関係を記述します
OCライブラリ、名前空間なし
コンポーネント化のポイントは合意にあります
個人的に
たとえば、URLルーティングの登録は、合意された情報を過去に渡すことです。サービスとして。
Lotusootには、サービスの呼び出し、ショートチェーンの登録、および呼び出しが含まれます
以下はサービスコールに焦点を当てており、ショートチェーンは省略されています。
風景、
プロジェクトには、A(プロトコル)とB(プロトコルの実装者、サービスの提供)の2つの依存関係があります
プロジェクトはAを参照し、プロトコル情報を知っています
プロジェクトはBを参照していません、プロジェクトはBについて何も知りません
- このようにして、プロジェクトはBを削除し、コンパイルを高速化します。
BはAに依存し、Aを参照し、Aのプロトコルを実装し、サービスを提供します
b、サービスに電話する
// 拿到 key
let lotus = s(AccountLotus.self)
// kv 取得提供服务的实例
let accountModule: AccountLotus = LotusootCoordinator.lotusoot(lotus: lotus) as! AccountLotus
// 调用服务
accountModule.login(username: "zhoulingyu", password: "wow") { (error) in
print(error ?? "1234")
}
复制代码
-
3番目のステップ、サービスの呼び出しは非常に簡単です
-
ステップ2は非常にエキサイティングで、Swiftコンパイル時の静的機能を最大限に活用します
コンパイル時に決定されるプロトコルのメソッド
いくつかのパラメータが必要です。どのタイプで、一般的に明示的に使用できます。
パラメータ辞書が表示されない、ああ、これは何ですか
// 第 2 步。从下面取
// 键值对,值是提供服务的对象
var lotusootMap: Dictionary = Dictionary<String, Any>()
复制代码
- ステップ1、キーを取得します
ここでは、プロトコル名がキーとして使用されています
// 使用泛型,取其描述
// 协议,转协议名
public extension String {
init<Subject>(_ instance: Subject) {
self.init(describing: instance)
}
}
/// 通过 Subject 快速获取字符串
public func s<Subject>(_ instance: Subject) -> String {
return String(instance)
}
复制代码
c、登録サービス
1、プロジェクトはBをインポートしません(サービスを提供します)、Bの機能をどのように使用しますか?
public static func registerAll(serviceMap: Dictionary<String, String>) {
for (lotus, lotusootName) in serviceMap {
// lotus, 协议名
// lotusootName, 包名.类名
let classStringName = lotusootName
// 反射,产生类
// 提供服务的类,一定是 NSObject 的子类,拥有 init 方法 ( 这是个约定 )
let classType = NSClassFromString(classStringName) as? NSObject.Type
if let type = classType {
// 产生对应的实例,强转为遵守协议的 ,即可
let lotusoot = type.init()
register(lotusoot: lotusoot, lotusName: lotus)
}
}
}
复制代码
2、ここではPythonスクリプトを使用して登録し、コンパイル時に情報を取得します协议名:包名.类名
慣例により、マーク
// @NameSpace(ZLYAccountModule)
// @Lotusoot(AccountLotusoot)
// @Lotus(AccountLotus)
class AccountLotusoot: NSObject, AccountLotus {}
复制代码
タグを見つけ、統合し、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)
复制代码
- すべての迅速なファイルを確認します
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'):
// 获取标记的配置
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)
上に表示されているキー(プロトコル名)
@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を作成することです
実行時に開始
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
LotusootCoordinator.registerAll()
return true
}
复制代码
登録は、[プロトコル名:パッケージ名。クラス名]の辞書として、今書いたplistを読むことです。
@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>)
}
}
复制代码
上記をエコーします
動的アイデアを入力し、KVを動的に登録します(プロトコル名:サービスライブラリ名。クラス名)
上の印象がありますが、シーンを知っていればできます
文章が長い場合は、文章を書いてください。
私を反映する方法、10年の実務経験?
上記はありません、単語の数を補うことを主張します
1.プロジェクトはキー(プロトコル名)を取得します、はい
2.プロジェクトはすべての依存関係情報を取得します
MachO
できます
3, project 拿到服务类的名称
确保 module B 的类名 = key ( 协议 ) + Cls
3.1 ,MachO
拿到所有依赖库的名称, 每一个 + “.” + key ( 协议 ) + Cls
= MachO
拿到所有依赖库的名称, 每一个 + “.” + module B 的类名
然后,看能不能实例化,
能够实例化,就 OK
试了一圈,不能够实例化,就报错
可能依赖 B, 没有添加
可能依赖 B 的类名,写错了
3.2 project 拿到服务类的名称, 优雅的
确保 module B 的类名 = key ( 协议 ) + Cls,
硬编码,是不好的
- 依赖 A ( 放协议的 ), 添加一个协议
public protocol Maid{
var name: String{ get }
}
复制代码
- module B 里面,必须有一个叫 key (协议) + C 的类
该类,遵守 Maid
协议。
通过协议属性,返回 B 中服务类的名称
class AccountLotusC: NSObject, Maid{
var name: String{
return String(reflecting: AccountLotusoot.self)
}
}
复制代码
这个过程,与上文模块化利用协议的设计,比较一致
约定是,实现协议的服务模块,
一定有一个 key + C 的类
提供服务类的名称
硬编码,比较轻微
代码实现
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()
// 处理所有的包,系统的,用户的
for i in 0..<cnt{
if let tmp = _dyld_get_image_name(i){
let name = String(validatingUTF8: tmp)
// 系统的,不用管
if let candidate = name, candidate.hasPrefix("/Users"){
if let tmp = candidate.components(separatedBy: "/").last{
// 去除 project 的
if tmp != mainName{
// 拿到用户依赖
result.append(tmp)
}
}
}
}
}
return result
}()
复制代码
以上,模拟器 OK, 真机没试过 ( 手头没开发证书 )
2,包名 + 类名的验证
@objc public static func lotusoot(lotus: String) -> Any? {
// 已经缓存了
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 {
// 实例化,助手类
let assist = type.init()
if let maid = assist as? Maid{
// 拿到 module B 的服务类的名称
let classType = NSClassFromString(maid.name) as? NSObject.Type
if let type = classType {
// 将 module B 的服务类,实例化
let lotusoot = type.init()
register(lotusoot: lotusoot, lotusName: lotus)
}
// 默认是,一个 module 一个服务类,
// 排除掉,使用过的用户类
LotusootCoordinator.sharedInstance.moduleNames.remove(at: i)
break
}
}
i+=1
}
if let val = sharedInstance.lotusootMap[lotus]{
return val
}
else{
fatalError("name Module of" + lotus)
}
}
}
复制代码