傳送門
Objective-C 一個一直以來令人詬病的地方就是沒有命名空間,在應用開發(fā)時寇窑,所有的代碼和引用的靜態(tài)庫最終都會被編譯到同一個域和二進制中鸦概。這樣的后果是一旦我們有重復的類名的話,就會導致編譯時的沖突和失敗甩骏。為了避免這種事情的發(fā)生窗市,Objective-C 的類型一般都會加上兩到三個字母的前綴,比如 Apple 保留的 NS 和 UI 前綴饮笛,各個系統(tǒng)框架的前綴 SK (StoreKit)咨察,CG (CoreGraphic) 等。Objective-C 社區(qū)的大部分開發(fā)者也遵守了這個約定福青,一般都會將自己名字縮寫作為前綴摄狱,把類庫命名為 AFNetworking 或者 MBProgressHUD 這樣脓诡。這種做法可以解決部分問題,至少我們在直接引用不同人的庫時沖突的概率大大降低了媒役,但是前綴并不意味著不會沖突祝谚,有時候我們確實還是會遇到即使使用前綴也仍然相同的情況。另外一種情況是可能你想使用的兩個不同的庫刊愚,分別在它們里面引用了另一個相同的很流行的第三方庫踊跟,而又沒有更改名字。在你分別使用這兩個庫中的一個時是沒有問題的鸥诽,但是一旦你將這兩個庫同時加到你的項目中的話商玫,這個大家共用的第三方庫就會和自己發(fā)生沖突了。
在 Swift 中牡借,由于可以使用命名空間了拳昌,即使是名字相同的類型,只要是來自不同的命名空間的話钠龙,都是可以和平共處的炬藤。和 C# 這樣的顯式在文件中指定命名空間的做法不同,Swift 的命名空間是基于 module 而不是在代碼中顯式地指明碴里,每個 module 代表了 Swift 中的一個命名空間沈矿。也就是說,同一個 target 里的類型名稱還是不能相同的咬腋。在我們進行 app 開發(fā)時羹膳,默認添加到 app 的主 target 的內容都是處于同一個命名空間中的,我們可以通過創(chuàng)建 Cocoa (Touch) Framework 的 target 的方法來新建一個 module根竿,這樣我們就可以在兩個不同的 target 中添加同樣名字的類型了:
- 在swift 中存在命名空間陵像,同一命名空間下全局共享.
- 第三方框架使用:直接拖入項目中,從屬于一個命名空間寇壳,很可能沖突(所以盡量用cocoapod)
- NSClassFromString(反射機制): 最重要的目的醒颖,就是解耦 。例子:(反射機制和工廠方法)
// MyFramework.swift
// 這個文件存在于 MyFramework.framework 中
public class MyClass {
public class func hello() {
print("hello from framework")
}
}
// MyApp.swift
// 這個文件存在于 app 的主 target 中
class MyClass {
class func hello() {
print("hello from app")
}
}
在使用時壳炎,如果出現(xiàn)可能沖突的時候泞歉,我們需要在類型名稱前面加上 module 的名字 (也就是 target 的名字):
MyClass.hello()
// hello from app
MyFramework.MyClass.hello()
// hello from framework
因為是在 app 的 target 中調用的,所以第一個 MyClass 會直接使用 app 中的版本冕广,第二個調用我們指定了 MyFramework 中的版本疏日。
另一種策略是使用類型嵌套的方法來指定訪問的范圍。常見做法是將名字重復的類型定義到不同的 struct 中撒汉,以此避免沖突。這樣在不使用多個 module 的情況下也能取得隔離同樣名字的類型的效果:
struct MyClassContainer1 {
class MyClass {
class func hello() {
print("hello from MyClassContainer1")
}
}
}
struct MyClassContainer2 {
class MyClass {
class func hello() {
print("hello from MyClassContainer2")
}
}
}
使用時:
MyClassContainer1.MyClass.hello()
MyClassContainer2.MyClass.hello()
其實不管哪種方式都和傳統(tǒng)意義上的命名空間有所不同涕滋,把它叫做命名空間睬辐,更多的是一種概念上的宣傳。不過在實際使用中只要遵守這套規(guī)則的話,還是能避免很多不必要的麻煩的溯饵,至少唾手可得的是我們不再需要給類名加上各種奇怪的前綴了侵俗。
實戰(zhàn):通過字符串獲取 類
在 AppDelegate 中設置window 的根控制器
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
window?.backgroundColor = UIColor.white
// 設置根控制器,需要添加命名空間 -》 通常是 "項目名.ClassName"
// 注意: 項目名 不能有 數(shù)字 特殊符號
// (1) 獲取命名空間
let nameSpace = Bundle.main.infoDictionary?["CFBundleName"] as! String
//(2) 拼接
let clsName = nameSpace + "." + "ViewController"
//AnyClass? ->視圖控制器的類型
let cls = NSClassFromString(clsName) as? UIViewController.Type
// 使用類名創(chuàng)建 控制器
let vc = cls?.init()
window?.rootViewController = vc
window?.makeKeyAndVisible()
return true
}