【问题标题】:Initialization of a UIViewController with default values consisted of singletons使用由单例组成的默认值初始化 UIViewController
【发布时间】:2017-10-26 14:49:24
【问题描述】:

尝试重构我的代码以避免必须在各处引用共享实例,而是我想通过自定义初始化程序注入它们。我对 Swift 初始化的有限理解阻止了我这样做。

这是我的 ViewController,减去方法和样板:

class LoginVC: UIViewController {
    let dataManager: DataManager
    let restManager: RestManager
    let defaults: UserDefaults

    init(defaults: UserDefaults = .standard, dataManager: DataManager = .sharedInstance, restManager: RestManager = .sharedInstance) {
      self.defaults = defaults
      self.dataManager = dataManager
      self.restManager = restManager
      super.init(nibName: nil, bundle: nil)
   }
}

我已经提供了默认值,这些默认值是在各自的 DataManager 和 RestManager 单例类中声明为静态常量的共享实例。计划在每个引用了这些单例的 ViewController 中执行此操作。无论如何,当编译器抱怨我必须提供所需的初始化程序 init(coder: aDecoder) 时,我的问题就出现了。

没问题,但是实施后……

    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

...编译器再次抱怨,这一次

Blockquote 属性“self.defaults”未在 super.init 调用时初始化

我想这是有道理的,因为需要初始化?据我所知,是一个委托初始化(可能是我在这里完全弄错了)。我不知道如何将自定义 init 的默认参数传递给此初始化程序的超级 init,或者是否有可能。

我尝试了一种解决方法,方法是将常量更改为可变变量,并像这样将它们隐式展开:

class LoginVC: UIViewController {
    var dataManager: DataManager!
    var restManager: RestManager!
    var defaults: UserDefaults!

    init(defaults: UserDefaults = .standard, dataManager: DataManager = .sharedInstance, restManager: RestManager = .sharedInstance) {
      self.defaults = defaults
      self.dataManager = dataManager
      self.restManager = restManager
      super.init(nibName: nil, bundle: nil)
   }
   required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder) 
   }
}

这种解决方法实际上可以编译和构建,但是一旦 viewDidLoad 中的 userDefaults 被解包,应用程序就会崩溃,因为它们有一个 nil 值。尽管它们在自定义初始化程序的参数中被默认为默认值,但它们都具有 nil 值,这让我相信我已经彻底搞砸了。

任何帮助/澄清将不胜感激,在此先感谢。

【问题讨论】:

    标签: swift dependency-injection uiviewcontroller initialization singleton


    【解决方案1】:

    不确定这是您想要做的,但我建议您使用此解决方案

    extension UIViewController {
    
        var defaults: UserDefaults {
            get {
                return .standard
            }
        }
    }
    

    所以在每个UIViewController 中你可以做self.defaults

    如果您希望您的某些UIViewControllers 有其他引用,您可以这样做

    //create protocol with all vars
    protocol References {
        var defaults: UserDefaults {get}
    }
    
    //create extension with default implementation
    extension References {
        var defaults: UserDefaults {
            get {
                return .standard
            }
        }
    }
    
    //add this protocol to all UIViewControllers
    extension UIViewController: References {
    }
    
    //or create new class with references
    class ReferenceViewController: UIViewController, References {
    }
    
    //override reference in some view controller if needed 
    class AnotherReferencesViewController: UIViewController { //or ReferenceViewController 
        var defaults: UserDefaults {
            get {
                //something new
                return .standard
            }
        }
    }
    

    【讨论】:

    • 感谢通过协议注入它们的想法,我已经实现了它,它就像一个魅力!仍然不确定为什么我的方法不起作用,但再次感谢。
    猜你喜欢
    • 2014-08-25
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-22
    • 2019-09-10
    • 1970-01-01
    • 2012-01-16
    相关资源
    最近更新 更多