我看不出为什么你需要通过全局状态访问userModel或someManager(是的 - 单身人士就是这样)。
为什么不把它设置在你需要的地方?
“依赖注入”是一个5美元概念的25美元术语。 这并不是说这是一个坏词...
依赖注入意味着 给一个对象的实例变量。真。而已。
- 詹姆斯岸:Dependency Injection Demystified
无论是构建
class C {
let currentUser: UserModel
let someManager: SomeManager
init(currentUser:UserModel, someManger:SomeManager) {
self.currentUser = currentUser
self.someManager = someManager
}
}
或通过属性时做到这一点。如果您需要确保所有属性都设置,做这样的事情:
class MyController: UIViewController {
var currentUser: UserModel? {
didSet{
self.configureIfPossible()
}
}
var someManager: SomeManager?{
didSet{
self.configureIfPossible()
}
}
func configureIfPossible(){
if let currentUser = self.currentUser, someManager = self.someManager {
// configure
}
}
}
在我目前的项目,我们有,每一个依赖必须从类的外部可见的和可配置的策略。
一个例子:
class LibrarySegmentViewController: BaseContentViewController {
var userDefaults: NSUserDefaults?
var previousSorting : LibrarySortingOrder = .AZ
var sorting : LibrarySortingOrder {
set{
self.previousSorting = sorting
if let filterMode = self.filterMode {
self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting")
}
self.setupIfReady()
}
get{
if let filterMode = self.filterMode {
if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) {
return s
}
}
return .Date
}
}
}
所以你可以看到,我们甚至使用属性引用NSUserDefaults.standardUserDefaults()
。我们这样做是因为我们可以在测试过程中通过新的实例,而不会有更大的嘲讽麻烦。
这是为什么不直接使用singleton的最主要原因:依赖关系是隐藏的,在测试和重构过程中可能会咬你。另一个例子是一个隐藏在代码中的API客户端单例,在测试过程中执行不需要的联网请求。如果它是从被测试类之外设置的,则可以传入一个模拟网络客户端,该客户端不会执行任何请求,但会返回测试数据。
所以即使你使用单例,你也应该把它作为一个依赖关系传入。
我通常使用我的管理类的单例实例,它仍然存在“全局方法”的问题,但许多API使用相同的技术,我认为这些案例是最好的。 – UlyssesR