优化Swift的构建时间

前端之家收集整理的这篇文章主要介绍了优化Swift的构建时间前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


原文: Regarding Swift build time optimizations 

作者: Robert Gummesson 

译者: 孙薇 

审校: 唐小引(@唐门教主),欢迎技术投稿、约稿,给文章纠错,请发送邮件tangxy@csdn.net


上周我拜读了Nickoneill的佳作《加速Swift的构建》,之后便不由稍微换了个角度来看待Swift的代码


目前有一个新问题出现:是否该将一行可以算是简洁的代码重构为9行代码,以便符合编译器的需求?对于代码来说,简洁与编译器友好孰轻孰重?其实,这取决于项目的规模以及开发者的意愿。


等等,有一个Xcode插件


在举例之前,我先强调一下手动过滤日志文件是非常耗时的。有人设计出了终端命令来简化这一步骤,不过我的方法更进一步,使用了Xcode插件




虽然初衷只是为了找到并修复最耗时的部分,不过目前我的看法也已经发生了变化:将该过程当成迭代的过程。这样的做法不仅可以让代码构建效率更高,也能在最开始就防止项目中出现过于耗费时间的函数


不少的惊喜


我时常来来回回地查看不同的Git branch,等待一个项目花费很长时间编译结束,一直没想出来为什么一个小项目(大约2万行Swift代码)要花那么久时间构建。


在了解到真正的原因后,我必须承认:一行代码也需要好几秒来编译这件事吓了我一跳。


我们来看几个例子!


空合运算符(Nil Coalescing Operator)


很显然,编译器肯定不喜欢第一种编译方法,在拆成两个视图之后,构建时间减少了99.4%。


// Build time: 5238.3ms

return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22,height: bounds.height)


// Build time: 32.4ms

var padding: CGFloat = 22

if let rightView = rightView {

    padding += rightView.bounds.width

}


if let leftView = leftView {

    padding += leftView.bounds.width

}

return CGSizeMake(size.width + padding,bounds.height)


ArrayOfStuff + [Stuff]


代码中经常是像下面这样:


return ArrayOfStuff + [Stuff]

// rather than

ArrayOfStuff.append(stuff)

return ArrayOfStuff


我经常会这样写代码,而这种方式对代码的构建时间有很大影响。下面是差距最大的一个案例,构建时间减少了97.9%。


// Build time: 1250.3ms

let systemOptions = [ 7,14,30,-1 ]

let systemNames = (0...2).map{ String(format: localizedFormat,systemOptions[$0]) } + [NSLocalizedString("everything",comment: "")]

// Some code in-between 

labelNames = Array(systemNames[0..<count]) + [systemNames.last!]


// Build time: 25.5ms

let systemOptions = [ 7,-1 ]

var systemNames = systemOptions.dropLast().map{ String(format: localizedFormat,$0) }

systemNames.append(NSLocalizedString("everything",comment: ""))

// Some code in-between

labelNames = Array(systemNames[0..<count])

labelNames.append(systemNames.last!)


三元运算符(Ternary operator)


使用if else语句代替了三元运算符,而不进行其它任何改动,构建时间就能缩短92.9%。如果用for循环来代替map,构建时间又会缩短75%(不过for循环太伤眼了)。


// Build time: 239.0ms

let labelNames = type == 0 ? (1...5).map{type0ToString($0)} : (0...2).map{type1ToString($0)}


// Build time: 16.9ms

var labelNames: [String]

if type == 0 {

    labelNames = (1...5).map{type0ToString($0)}

} else {

    labelNames = (0...2).map{type1ToString($0)}

}


在CGFloat中去掉CGFloat


这句话有点费解,其实在CGFloat中,有些括号是多余的,清除掉之后,构建时间会缩短99.9%。


// Build time: 3431.7 ms

return CGFloat(M_PI) * (CGFloat((hour + hourDelta + CGFloat(minute + minuteDelta) / 60) * 5) - 15) * unit / 180


// Build time: 3.0ms

return CGFloat(M_PI) * ((hour + hourDelta + (minute + minuteDelta) / 60) * 5 - 15) * unit / 180


Round()


这个真的很奇怪,下面样例中的变量混合了本地与实例变量,问题很可能不在rounding本身,而是由于在方法中混用代码而导致的,去掉它之后就能大幅缩减所用的时间,准确来讲耗费时长减少了97.6%。


// Build time: 1433.7ms

let expansion = a — b — c + round(d * 0.66) + e

// Build time: 34.7ms

let expansion = a — b — c + d * 0.66 + e


注意:所有的对比测量都是在MacBook Air(13英寸,Mid 2013款)上进行的。


试一下吧


无论你是否遇到了构建速度缓慢的问题,了解到底是什么会让编译器遇到混乱情况都是很有用的。我肯定你也能发现不少惊喜,作为参考,下面是在我的项目中需要花费5秒多时间构建的完整代码


import UIKit


class CMExpandingTextField: UITextField {


    func textFieldEditingChanged() {

        invalidateIntrinsicContentSize()

    }


    override func intrinsicContentSize() -> CGSize {

        if isFirstResponder(),let text = text {

            let size = text.sizeWithAttributes(typingAttributes)

            return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22,height: bounds.height)

        }

        return super.intrinsicContentSize()

    }

}





第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。


原文链接:https://www.f2er.com/swift/821362.html

猜你在找的Swift相关文章