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

优化Swift的构建时间

发布时间:2020-12-14 05:16:51 所属栏目:百科 来源:网络整理
导读:原文: Regarding Swift build time optimizations? 作者: Robert Gummesson? 译者: 孙薇? 审校: 唐小引(@唐门教主),欢迎技术投稿、约稿,给文章纠错,请发送邮件tangxy@csdn.net 上周我拜读了 Nickoneill 的佳作 《加速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)。


(编辑:李大同)

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

    推荐文章
      热点阅读