Swift:让人眼前一亮的初始化方式
有条传播得很广的 tweet 讲到用位置参数(positional references)来初始化 Swift 常量:
原始代码见这个 gist(译注:原 gist 代码缩进太乱,搬运过来整理如下): import UIKit import XCPlayground class ViewController: UIViewController { func action() { print("Bing!") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .whiteColor() let mySwitch : UISwitch = { view.addSubview($0) CenterViewInSuperview($0,horizontal: true,vertical: true) $0.addTarget(self,action: "action",forControlEvents: .TouchUpInside) return $0 }(UISwitch()) let _ : UILabel = { view.addSubview($0) CenterViewInSuperview($0,vertical: false) $0.text = "Toggle me" $0.font = UIFont.boldSystemFontOfSize(36) ConstrainViews("V:[view1]-30-[view2]",views: $0,mySwitch) return $0 }(UILabel()) } } ViewController() XCPlaygroundPage.currentPage.liveView = ViewController() XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 由于这条 tweet 太简短,而且没有像我预期的那样运作,这让我很困惑。因此我想在这儿写一篇关于这个问题更详细的文章。 问题声明常量后,在一个紧接着的闭包中进行初始化,而不是之后在 let purpleView: UIView = { // 在此初始化 view // 直接叫 "view" 真的好吗? let view = UIView() view.backgroundColor = .purpleColor() return view }() 我总是觉得在闭包中多命名一个 解决方案当我看到 tweet 中用 // 声明:以下代码无法运行 let yellowView: UIView = { $0.backgroundColor = .yellowColor() return $0 }() 但这没法运行...再仔细查看 @ericasadun 的代码,我意识到必须在闭包执行时,传入一个初始化好的 let yellowView: UIView = { $0.backgroundColor = .yellowColor() return $0 // 确保下一行的括号内要传入 UIView() }(UIView()) 当然这一次就能运行了! 结论我确实很喜欢在这里用 加入我们 9 月 1 ~ 2 日在纽约市举办的 Swift 社区庆祝会?`(Swift Community Celebration)吧,用这个优惠码 NATASHATHEROBOT 减 $100! 更新@khanlou 指出有个叫 Then 的库更赞,能够写出可读性更好的代码: let label = UILabel().then { $0.textAlignment = .Center $0.textColor = .blackColor() $0.text = "Hello,World!" } 但我并不是很乐意把这个库导入到我的项目中,@khanlou 再次指出这个库只有 15 行代码,于是我的最终想法是把这 15 行代码复制到我的项目中!(译注:既然只有 15 行代码,下面搬运过来方便阅读) import Foundation public protocol Then {} extension Then where Self: Any { /// Makes it available to set properties with closures just after initializing. /// /// let label = UILabel().then { /// $0.textAlignment = .Center /// $0.textColor = UIColor.blackColor() /// $0.text = "Hello,World!" /// } public func then(@noescape block: inout Self -> Void) -> Self { var copy = self block(©) return copy } } extension Then where Self: AnyObject { /// Makes it available to set properties with closures just after initializing. /// /// let label = UILabel().then { /// $0.textAlignment = .Center /// $0.textColor = UIColor.blackColor() /// $0.text = "Hello,World!" /// } public func then(@noescape block: Self -> Void) -> Self { block(self) return self } } extension NSObject: Then {} 你也可以看看 @ericasadun 这个不错的解决方案!(译注:即这个 gist,代码搬运如下) // @discardableResult to be added // @noescape needs to move to type annotation // needs to add _ for item public func with<T>(item: T,@noescape update: (inout T) throws -> Void) rethrows -> T { var this = item; try update(&this); return this }
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |