Swift 编译优化(4) - 代码优化

iOS 编译优化

编译项设置优化完之后,主要就是代码的优化了。Swift 耗时的主要就是类型检查,那么代码优化的重点就是 检查哪些表达式、函数 类型检查占用太长时间。

我们将代码编译优化的等级分为 【高】【中】【低】,逐一验证分析。

【高】编译优化项

复杂的运算

一个计算式

尽量不要超过两种运算符号,不要进行过多次运算。

第一种

这是一个最简单的类型推断。

csharp 复制代码
 func dictTest1() {
  let _ = [
    "x": 1.0,
    "y": 2.0,
    "w": 3.0,
    "h": 4.0
  ]
 }

说明信息: 系统只需简单的类型推断即可,由于比较简单,以系统的能力很轻松的就推断出来了。

编译耗时: 1ms。

第二种

在第一种的基础上,x的值使用加法计算出来。

csharp 复制代码
 func dictTest2() {
  let _ = [
    "x": 1.0 + 1,
    "y": 2.0 ,
    "w": 3.0,
    "h": 4.0
  ]
 }

说明信息: 同一种运算方式得到的值,还是该类型。所以系统还是很容易的就推断出来了。

编译耗时: 1ms。

第三种

在第二种的基础上,x的值使用 加法 和 减法 计算出来。

csharp 复制代码
 func dictTest3() {
  let _ = [
    "x": 1.0 + 1 - 1,
    "y": 2.0 ,
    "w": 3.0,
    "h": 4.0
  ]
 }

说明信息: 两种运算方式(加法 和 减法),会影响编译耗时。

编译耗时: 8ms。

第四种

csharp 复制代码
 func dictTest4() {
  let _ = [
    "x": 1.0 + 1 - 1 + 3 * 3,
    "y": 2.0 ,
    "w": 3.0,
    "h": 4.0
  ]
 }

说明信息: 三种运算方式(加法 , 减法 和 乘法),会严重影响编译耗时。

编译耗时: 695ms。

第五种

csharp 复制代码
 func dictTest5() {
    let _ = [
        "x": 1.0 + 1 - 1 + 3 * 3,
        "y": 1.0 + 1 - 1 + 3 * 3,
        "w": 3.0,
        "h": 4.0
    ]
 }

说明信息: 两个值的三种运算方式(加法 , 减法 和 乘法),会严重影响编译耗时。

编译耗时: 1382ms。

第六种

ini 复制代码
 func dictTest6() {
    let x = 1.0 + 1 - 1 + 3 * 3
    let y = 1.0 + 1 - 1 + 3 * 3
    let _ = [
        "x": x,
        "y": y,
        "w": 3.0,
        "h": 4.0
    ]
 }

说明信息: 将x和y,拿出来单独运算,由于减少了推断的层级(减少了字典的类型推断量),但是减少有限。

编译耗时: 1362ms。

第七种

测试发现,一个计算有四种运算符号,就 Run 不动了。

csharp 复制代码
 func dictTest7() {
    let x = 1.0 + 1 - 1 + 3 * 3 + 3 / 2
    let _ = [
        "x": x,
        "y": 2.0 ,
        "w": 3.0,
        "h": 4.0
    ]
 }

长时间的等待之后,编译器会报错:

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

第八种

推断中带可选值解包。

swift 复制代码
 let value: CGFloat? = 4
 ​
 let _ = [
    "x": 1.0 + 1 - 1 + 3 * 3,
    "y": 1.0 + 1 - 1 + 3 * 3,
    "w": CGFloat((value ?? 0) * 4 - 5),
    "h": 4.0
 ]

说明信息: 可选值的解包也会影响编译时间。

编译耗时: 1461ms。

第九种

推断中带可选值解包。

swift 复制代码
let value: CGFloat? = 4

let _ = [
    "x": 1.0 + 1 - 1 + 3 * 3,
    "y": 1.0 + 1 - 1 + 3 * 3,
    "w": CGFloat((value ?? 0) * 4 - 5),
    "h": 4.0
]

说明信息: 可选值的解包也会影响编译时间。

编译耗时: 1461ms。

String的拼接

csharp 复制代码
// 编译耗时: 0ms
func stringTest1() {
    let str = "123"
}

// 编译耗时: 6ms
func stringTest2() {
    let str = "123" + "456"
}

// 编译耗时: 1ms
func stringTest3() {
    let str1 = "123"
    let str2 = "456"
    let str = "(str1) + (str2)"
}

// 编译耗时: 5ms
func stringTest4() {
    let str1 = "123"
    let str2 = "456"
    let str = str1.appending(str2)
}

字符串的拼接中,优先选择 "(str1) + (str2)" 这种方式。

类型推断

在Swift中定义变量时可以不带类型声明,编译器会根据初始化的值去猜测变量类型。这为Swift开发者提供便利的同时,也增加了编译器的负担。

从减少编译时间的角度考虑:给每个变量定义都加上类型声明,这样编译器负担最小。

为了写 "Swift" 代码,对于简单的变量定义,添不添加类型声明,编译时间都差不多。

但对于下面复杂的类型,最好还是加上类型。

csharp 复制代码
// 方法编译耗时为: 8ms
func functionOne() {
    let myCompany = [
        "employees": [
            "employee 1": ["attribute": "value"],
            "employee 2": ["attribute": "value"],
            "employee 3": ["attribute": "value"],
            "employee 4": ["attribute": "value"],
            "employee 5": ["attribute": "value"],
            "employee 6": ["attribute": "value"],
            "employee 7": ["attribute": "value"],
            "employee 8": ["attribute": "value"],
            "employee 9": ["attribute": "value"],
            "employee 10": ["attribute": "value"],
            "employee 11": ["attribute": "value"],
            "employee 12": ["attribute": "value"],
            "employee 13": ["attribute": "value"],
            "employee 14": ["attribute": "value"],
            "employee 15": ["attribute": "value"],
            "employee 16": ["attribute": "value"],
            "employee 17": ["attribute": "value"],
            "employee 18": [1, 2, 3],
            "employee 19": "2",
            "employee 20": 1,
        ]
    ]
}

让系统推断类型,该方法编译耗时为: 8ms。

swift 复制代码
//方法编译耗时为: 4ms
func functionTwo() {
    let myCompany1: [String: Any] = [
        "employees": [
            "employee 1": ["attribute": "value"],
            "employee 2": ["attribute": "value"],
            "employee 3": ["attribute": "value"],
            "employee 4": ["attribute": "value"],
            "employee 5": ["attribute": "value"],
            "employee 6": ["attribute": "value"],
            "employee 7": ["attribute": "value"],
            "employee 8": ["attribute": "value"],
            "employee 9": ["attribute": "value"],
            "employee 10": ["attribute": "value"],
            "employee 11": ["attribute": "value"],
            "employee 12": ["attribute": "value"],
            "employee 13": ["attribute": "value"],
            "employee 14": ["attribute": "value"],
            "employee 15": ["attribute": "value"],
            "employee 16": ["attribute": "value"],
            "employee 17": ["attribute": "value"],
            "employee 18": [1, 2, 3],
            "employee 19": "2",
            "employee 20": 1,
        ]
    ]
}

告诉系统明确的类型,该方法编译耗时为: 4ms。

CGSize,CGRect,Dictionary,Array

不要在实现中,有计算,解包,三目运算等。

ini 复制代码
❌❌❌❌❌❌
let size = CGSize(width: 50 / 3 + 3, height: 2 + 4 - 4)
let rect = CGRect(x: isTrue ? 40 : 30, y: 50 * 3 + 20, width: 5, height: 5)
let dict = [
    "a": (5 + 3 / 2) + min(3, value * 3)
]

删除Xib

xib文件的编译是很耗时的。我们的项目中删的已经差不多了。

【中】编译优化项

Array的拼接

推荐使用append(contentsOf: arr2)的方式。

ini 复制代码
func functionOne() {
    let arr1 = [1, 2, 3, 4]
    let arr2 = [5, 6, 7, 8]
    let arr = arr1 + arr2
}

该方法编译耗时 8秒

scss 复制代码
func functionTwo() {
    var arr1 = [1, 2, 3, 4]
    let arr2 = [5, 6, 7, 8]
    arr1.append(contentsOf: arr2)

}

该方法编译耗时 4秒

转换为String

ini 复制代码
let intA = 1
let string = String(intA)

这样转换成字符串,耗时 1ms。

ini 复制代码
let intA = 1
let string = "(intA)"

这样转换成字符串,耗时 8ms。

提前计算

不要在一个表达式中既做判断,又做计算。 如果条件允许,避免计算。 越复杂的计算,编译耗时越长。

csharp 复制代码
// 编译耗时:5ms
func functionOne() {
    let time = 10000
    if time > 60 * 60 * 24 + 3 {
        
    }
}

// 编译耗时:1ms
func functionTwo() {
    let time = 10000
    let limit = 60 * 60 * 24 + 3
    if time > limit {
        
    }
}

// 编译耗时:0ms
func functionThree() {
    let time = 10000
    if time > 8643 { // 60 * 60 * 24 + 3
        
    }
}

【低】编译优化项

三元运算符【低】

ini 复制代码
let letter = someBoolean ? "a" : "b"

三目运算符写法更加简洁,但会增加编译时间,如果想要减少编译时间,可以改写为下面的写法。

ini 复制代码
var letter = ""
if someBoolean { 
  letter = "a"
} else {
  letter = "b"
}

实测数据,没有本质的区别。 等待继续验证。

可选解包【低】

ini 复制代码
let v = optionalString ?? ""

这是 Swift 中的特殊语法,在使用 optional 类型时可以通过这样的方式设置 default value。但是这种写法本质上也是三目运算符。

bash 复制代码
if let string = optionalString {
    print("(string)")
}
相关推荐
茶底世界之下几秒前
导出进度不是一个百分比:AVFoundation 收尾阶段的状态建模
ios·swift
大熊猫侯佩9 分钟前
macOS27 上可变界面尺寸 iOS App 揭秘
macos·ios·swiftui
用户21816970493025 分钟前
LLVM
ios
茶底世界之下25 分钟前
为什么媒体源不能在回调仍执行时提前报告 finish?
swift
zeqinjie26 分钟前
Flutter 获取 iPhone Duo 预留区位置
前端·flutter·ios
二流小码农33 分钟前
鸿蒙开发:ArrayList,可不会让UI更新哦
android·ios·harmonyos
茶底世界之下33 分钟前
为什么视频处理器必须提前声明“它能处理什么帧”
swift
茶底世界之下1 小时前
录制结束,不代表视频文件已经交付:AVFoundation 录制完成状态的工程化判断
swift
茶底世界之下6 天前
为什么预览、录制、离线导出不能共享同一个背压策略?
ios·swift
2501_916007476 天前
苹果商店iOS应用上架费用全面解析:开发者计划与审核费用计算
android·ios·小程序·https·uni-app·iphone·webview