我定义了一个具有静态属性的全局结构,其中包含我在许多视图控制器中使用的值,如下所示:
public struct AppGlobal {
static var currentUser = UserModel()
static let someManager = SomeManager()
// Prevent others from initializing
private init() { }
}
那么在我的UIViewController
,我可以做这样的事情:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AppGlobal.currentUser.prop1 = "abc123"
AppGlobal.someManager.startUpdating()
}
}
这显然很方便,但闻起来真的很难闻。我相信依赖注入会在这里派上用场,但不确定如何。除了创建AppGlobal
单例属性之外,是否有更优雅的替代方法?
我不明白为什么你需要通过全局状态访问userModel或someManager(是的 - 单例就是这样)。
为什么不直接将其设置在您需要的地方?
"依赖注入"是一个25美元的术语,用于5美分的概念。 这并不是说这是一个糟糕的术语...
[...]
依赖注入手段 为对象提供其实例变量。真。就是这样。– 詹姆斯·肖尔:依赖注入揭秘
要么在施工期间这样做
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()
。我们这样做是因为我们可以在测试期间传入新的实例,而不会有更大的模拟麻烦。
这是为什么不直接使用单例的最重要原因:依赖项是隐藏的,可能会在测试和重构期间咬你。另一个示例是隐藏在代码中的 API 客户端单例,并在测试期间执行不需要的网络请求。如果它是从测试类外部设置的,则可以传入一个模拟的网络客户端,该客户端不执行任何请求,但返回测试数据。
因此,即使您使用单例,也应该将其作为依赖项传入。
如果这个问题是关于全局的,你应该看到这个线程:单身人士有什么不好?
但是,如果您想为单例的实现提供更好的设计,您可以尝试这样的事情:
class SingletonExample: NSObject {
static let sharedInstance: SingletonExample()
}
class OtherSingletonExample: NSObject {
static let sharedInstance: OtherSingletonExample()
}
然后,您可以在代码中的任何位置使用 SingletonExample.sharedInstance
和 OtherSingletonExample.sharedInstance
。
这个想法是将一个单例与另一个单例隔离开来,并将其作为类属性访问,而不是为任何内容创建一个大的全局结构。