如何在Swift中使用@IBOutlet属性正确实现延迟实例化 [英] How to properly implement lazy instantiation with an @IBOutlet property in Swift

查看:1751
本文介绍了如何在Swift中使用@IBOutlet属性正确实现延迟实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

   - (UIView *)headerView 
{
//如果你还没有加载头视图...
if(!_headerView){

//加载HeaderView.xib
[[NSBundle mainBundle ] loadNibNamed:@HeaderViewowner:self options:nil]
}

return _headerView;
}

Apple的Swift指南@IBOutlet:


当你在Swift中声明一个插座时,编译器会自动将类型转换为一个弱的隐式解包的可选项,并赋予它一个初始值nil。实际上,编译器替换@IBOutlet var name:Type with @IBOutlet weak var name:Type! = nil。


正如延迟加载属性在swift ,有几个不同的选项。在这篇文章中,他们没有一个明确提到使用@IBOutlet进行延迟初始化,所以我最好的实现他们的建议,并想知道什么是最佳实践。



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

  @IBOutlet var headerView:UIView {
//如果HeaderView尚未加载...
if!_headerView {
//加载HeaderView.xib
NSBundle.mainBundle()。loadNibNamed(HeaderView,owner:self ,options:nil)
}
return _headerView!
}
var _headerView:UIView? = nil

尝试#2(失败):使用@lazy 没有工作,因为@lazy需要一个初始化程序,但如果使用闭包,则@IBOutlet有与尝试#1相同的问题



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

  @IBOutlet var headerView:UIView 

func loadHeaderView {
//如果HeaderView尚未加载...
if!headerView {
//加载HeaderView.xib
println(加载HeaderView)
NSBundle.mainBundle()。loadNibNamed(HeaderView,owner:self,options:nil)
}
}

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


$ b b

那么,这怎么可以改进呢?



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



感谢

c> c> c> 只读计算属性。 @IBOutlet 属性需要是可变的,所以XIB / Storyboard可以做它的魔术,所以你需要实现它与getter和setter,如下: / p>

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


I am Learning iOS Development with Big Nerd Ranch's latest iOS book. I have chosen to implement their apps in Swift. In one of their apps, they have the following code in 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;
}

Apple's Swift guide on "@IBOutlet":

When you declare an outlet in Swift, the compiler automatically converts the type to a weak implicitly unwrapped optional and assigns it an initial value of nil. In effect, the compiler replaces @IBOutlet var name: Type with @IBOutlet weak var name: Type! = nil.

As it was pointed out in Lazy loading Properties in swift, there are a couple of different options. None of them in that post explicitly mention lazy initialization with @IBOutlet, so I've done by best to implement their suggestions, and would like to know what would be considered best practices.

Attempt #1(failed): following a similar pattern, as the example from AppDelegate.swift. This brings the issue "'IBOutlet' attribute requires property to be mutable"

@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

Attempt #2(failed): using any variation of "@lazy" with "@IBOutlet" didn't worked because "@lazy" needs an initializer, but if a closure is used, then "@IBOutlet" has the same issue as from Attempt #1

Attempt #3(successful?): this is the only way I was able to get this to work. I got the idea from a somewhat different question, Lazy property initialization in Swift. My understanding of what is happening is headerView is actually declared as "@IBOutlet weak var headerView : UIView! = nil", will only be initialized once with the TableViewController subclass I have, and that initialization will be "lazy" in that it only occurs when the TableViewController needs to be loaded.

@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
}

So, how can this be improved?

Is viewDidLoad() the correct function to use?

Thanks

解决方案

You aren't actually providing a closure for headerView with that code, you're declaring it as a read-only computed property. @IBOutlet properties need to be mutable so the XIB/Storyboard can do its magic, so you'd need to implement it with both a getter and a setter, like this:

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

这篇关于如何在Swift中使用@IBOutlet属性正确实现延迟实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆