加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Swift:让人眼前一亮的初始化方式

发布时间:2020-12-14 02:33:32 所属栏目:百科 来源:网络整理
导读:作者:Natasha The Robot,原文链接,原文日期:2016/05/25 译者:haolloyin;校对:saitjr;定稿:CMB 有条传播得很广的 tweet 讲到用位置参数(positional references)来初始化 Swift 常量: 原始代码见这个 gist(译注:原 gist 代码缩进太乱,搬运过来

作者:Natasha The Robot,原文链接,原文日期:2016/05/25
译者:haolloyin;校对:saitjr;定稿:CMB

有条传播得很广的 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 太简短,而且没有像我预期的那样运作,这让我很困惑。因此我想在这儿写一篇关于这个问题更详细的文章。

问题

声明常量后,在一个紧接着的闭包中进行初始化,而不是之后在 viewDidLoad 或其他类似的方法中进行设置,这在 Swift 中是很常见的写法(也确实是一种不错的写法!)。

let purpleView: UIView = {
    // 在此初始化 view
    // 直接叫 "view" 真的好吗?
    let view = UIView()
    view.backgroundColor = .purpleColor()
    return view
}()

我总是觉得在闭包中多命名一个 UIView 很难看(译注:注意看上面代码中原作者的注释),上面代码中有 purpleViewview 两个 UIView 实例,那么 view 是不是应该命名成 purpleView?我至今还没找到关于这种命名问题的好办法。

解决方案

当我看到 tweet 中用 $0 而不是很繁琐地命名变量时感到很兴奋,我立马尝试了一下:

// 声明:以下代码无法运行
let yellowView: UIView = {
    $0.backgroundColor = .yellowColor()
    return $0
}()

但这没法运行...再仔细查看 @ericasadun 的代码,我意识到必须在闭包执行时,传入一个初始化好的 UIView 实例:

let yellowView: UIView = {
    $0.backgroundColor = .yellowColor()
    return $0
 // 确保下一行的括号内要传入 UIView()
}(UIView())

当然这一次就能运行了!

结论

我确实很喜欢在这里用 $0 的写法,而不是显式地再命名一个变量。为啥我没想到这种方法呢,好气哦。然而现在我知道必须传入一个初始化好的 UIView(),这从逻辑上的确说得通。大概我以后都会用这种写法。在这里用 $0 这么优雅的写法,为啥不呢!

加入我们 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(&copy)
        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
}

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读