2016-02-19 86 views
2

我定义的全局结构与静态属性与我在我的许多视图控制器的使用值,如:替代Swift中的臭味全局变量?

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

我通常使用我的管理类的单例实例,它仍然存在“全局方法”的问题,但许多API使用相同的技术,我认为这些案例是最好的。 – UlyssesR

回答

5

我看不出为什么你需要通过全局状态访问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客户端单例,在测试过程中执行不需要的联网请求。如果它是从被测试类之外设置的,则可以传入一个模拟网络客户端,该客户端不会执行任何请求,但会返回测试数据。

所以即使你使用单例,你也应该把它作为一个依赖关系传入。

+0

这应该是正确的答案。依赖注入使得你的代码更具可测性,因为它使得你的依赖可以被替换和嘲弄。单身人士是反模式。它们导致紧密的耦合,这使得你的代码不易测试。 – pommes

3

如果这个问题是关于全球与否,你应该看到这个线程: What is so bad about singletons?

但是,如果你想要一个更好的设计为您实现一个单身的你可以尝试这样的事:

class SingletonExample: NSObject { 

    static let sharedInstance: SingletonExample() 
} 

class OtherSingletonExample: NSObject { 

    static let sharedInstance: OtherSingletonExample() 
} 

然后,您可以在代码中的任意位置使用SingletonExample.sharedInstanceOtherSingletonExample.sharedInstance

这个想法是将一个单例从另一个单例中分离出来,并以类属性的形式访问它,而不是为任何东西创建一个大的全局结构。