如何在Swift中用@IBOutlet属性正确实现懒惰的实例化

我正在用Big Nerd Ranch最新的iOS书籍学习iOS开发。 我select在Swift中实现他们的应用程序。 在他们的一个应用程序中,它们在Objective C中有以下代码:

- (UIView *)headerView { // If you have not loaded the header view yet... if (!_headerView) { // Load HeaderView.xib [[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil] } return _headerView; } 

苹果的“@IBOutlet”Swift指南:

当你在Swift中声明一个sockets时,编译器会自动将这个types转换成一个弱隐式解包的可选项,并赋予它一个初始值为nil的值。 实际上,编译器用@IBOutlet弱var名replace@IBOutlet var name:Type:Type! =无。

正如在懒惰加载属性在swift中指出的,有几个不同的选项。 他们中没有一个明确提到使用@IBOutlet进行惰性初始化,所以我已经尽了最大努力来实现他们的build议,并希望知道什么会被认为是最佳实践。

尝试#1(失败):遵循类似的模式,如AppDelegate.swift中的示例。 这带来了问题“'IBOutlet'属性需要属性是可变的”

 @IBOutlet var headerView : UIView { // If the HeaderView has not been loaded yet... if !_headerView { // Load HeaderView.xib NSBundle.mainBundle().loadNibNamed("HeaderView", owner: self, options: nil) } return _headerView! } var _headerView : UIView? = nil 

尝试#2(失败):使用“@lazy”和“@IBOutlet”的任何变体都不起作用,因为“@lazy”需要一个初始化程序,但是如果使用闭包,那么“@IBOutlet”的问题与从尝试#1

尝试#3(成功?):这是我能够得到这个工作的唯一途径。 我从一个有点不同的问题中得到了这个想法,Swift中的Lazy属性初始化 。 我对发生的事情的理解是,headerView实际上被声明为“@IBOutlet weak var headerView:UIView!= nil”,只会使用TableViewController子类初始化一次,并且初始化将会是“懒惰”当TableViewController需要加载。

 @IBOutlet var headerView : UIView func loadHeaderView() { // If the HeaderView has not been loaded yet... if !headerView { // Load HeaderView.xib println("loaded HeaderView") NSBundle.mainBundle().loadNibNamed("HeaderView", owner: self, options: nil) } } override func viewDidLoad() { super.viewDidLoad() loadHeaderView() tableView.tableHeaderView = headerView } 

那么,这怎么能改进呢?

viewDidLoad()是否使用正确的函数?

谢谢

你实际上并没有为这个代码提供一个closuresheaderView ,你声明它是一个只读的计算属性。 @IBOutlet属性需要是可变的,所以XIB / Storyboard可以实现它的魔法,所以你需要用getter和setter来实现它,就像这样:

 @IBOutlet var headerView : UIView { get { if !_headerView { NSBundle.mainBundle().loadNibNamed("HeaderView", owner: self, options: nil) } return _headerView! } set { _headerView = newValue } } var _headerView : UIView? = nil 

一个懒惰的sockets没有任何意义 – 如果它是一个sockets,它装载笔尖时,而不是从代码填充。 如果你从代码加载它,它不需要是一个sockets,所以你可以使用@lazy。

下面的作品…

 @IBOutlet lazy var headerView : UIView? = { return NSBundle.mainBundle().loadNibNamed("HeaderView", owner: self, options: nil)[0] as? UIView }() 

然后设置headerView

 override func viewDidLoad() { super.viewDidLoad() tableView.tableHeaderView = headerView } 

你也可以使用didSet:

  @IBOutlet weak var profileImageView: UIImageView! { didSet { profileImageView.image = profileImage profileImageView.layer.masksToBounds = true profileImageView.layer.cornerRadius = 16 } }