2016-08-14 133 views
6

在示例代码中,我看到了两种不同风格的声明对象。一个优于另一个的优点是什么?这两种声明风格之间有什么区别/优点

两个被声明为 var btn: UIButton!

风格1:

btn = UIButton() 
btn.translatesAutoresizingMaskIntoConstraints = false 
btn.layer.borderColor = UIColor.blue.cgColor 
btn.layer.borderWidth = 1 
... 
self.view.addSubview(btn) 

风格2:

btn = { 
    let b = UIButton() 
    b.translatesAutoresizingMaskIntoConstraints = false 
    b.layer.borderColor = UIColor.blue.cgColor 
    b.layer.borderWidth = 1 
    ... 
    return b 
}() 
self.view.addSubview(btn) 

我目前看到的唯一的好处是,第二风格使得代码更清晰,当你有许多obj学分。你也可以在Xcode中折叠它们。还有其他优势吗?第二个版本不会在运行时“花费”更多的资源吗? 哪个更好?

感谢

+0

我不知道这是否有所作为,但第二种模式只在所有设置完成后才会分配给'btn'(即不会在发生错误时保留'btn'半初始化) 。 – Thilo

+0

我认为这是有用的一个情况。当你想创建一个对象时,必须在创建时更改/分配一些值,例如一个具有可选属性的结构,init方法不能分配它。但是你同时想保持变量本身不变。 – Surely

+0

在任何情况下都不应将该按钮声明为隐式解包可选。 – nhgrif

回答

3

关闭初始化(您的第二个示例)有三大优势。

优势一:初始化let结构。你的例子使用了一个UIButton,这是一个类 - 一个引用类型。如果我们正在初始化一个结构为let,我们不能改变它。一旦我们将其初始化为let声明,我们就不能更改任何设置者,也不能调用标记为mutating的任何方法。关闭初始化允许我们在分配到let声明的变量之前完成此设置。

优点二:范围。我们初始化的闭包有自己的范围。它可以从封闭范围捕获变量,但范围内声明的变量在其外部不可用。这意味着我们不会在变量名称上发生冲突。这也意味着ARC可以在初始化完成时进行一些清理。

优点三:类/结构成员变量的在线初始化。我列出的前两个优点并不总是必要的,你通常可以在他们周围工作。但是,如果没有闭合初始化,如果你想在声明它的点初始化按钮,你被卡住的东西是这样的:

class MyViewController: UIViewController { 

    var button = UIButton() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // TODO: Set up button's properties 

     view.addSubview(button) 
    } 
} 

但随着闭合初始化,我们可以设置这些都建立在点宣言。

class MyViewController: UIViewController { 

    var button: UIButton = { 
     let button = UIButton() 
     // TODO: Set up button 
     return button 
    }() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     view.addSubview(button) 
    } 
} 
1

的差异在小例子相当琐碎,但可能会在更大,更复杂的软件更显著。

在第一个示例中,btn的状态暂时无效 - 直到完成所有属性分配为止。在第二个示例中,该按钮在分配给btn时完全构建。另外,第二个代码实际上是一个工厂方法,可以将其分离为一个单独的类并进行参数化。如果正在创建许多类似的按钮,这很有用。

将构建按钮和其他控件的职责分离为专业类是为了减少iOS应用程序中视图控制器的大小和复杂性而迈出的一步。