我已经定义了一个带有静态属性的全局结构,其中包含我在许多视图控制器中使用的值,如下所示:
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
单例属性?
答案 0 :(得分:5)
我无法理解为什么你需要通过全局状态访问userModel或someManager(是的 - 单身就是这样)。
为什么不把它设置在你需要的地方?
对于5美分概念,“依赖注入”是一个25美元的术语。 这并不是说这是一个坏词...... [...]
依赖注入意味着 给对象一个实例变量。真。就是这样。- James Shore: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()
。我们这样做是因为我们可以在测试期间传递新的实例,而不会有更大的嘲弄麻烦。
这是不直接使用单例的最重要原因:依赖项是隐藏的,可能会在测试和重构期间咬你。另一个例子是API客户端单例,它隐藏在代码中并在测试期间执行不需要的网络请求。如果它是从测试类的外部设置的,您只需传入一个模拟的网络客户端,该客户端不执行任何请求但返回测试数据。
因此,即使您使用单例,也应该将其作为依赖项传递。
答案 1 :(得分:3)
如果这个问题与全局有关,你应该看到这个帖子: What is so bad about singletons?
但是如果你想要一个更好的设计来实现单例,你可以尝试这样的事情:
class SingletonExample: NSObject {
static let sharedInstance: SingletonExample()
}
class OtherSingletonExample: NSObject {
static let sharedInstance: OtherSingletonExample()
}
然后,您可以在代码中的任何位置使用SingletonExample.sharedInstance
和OtherSingletonExample.sharedInstance
。
这个想法是将一个单例与另一个单独隔离,并将其作为类属性访问,而不是为任何东西创建一个大的全局结构。