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)")
}
相关推荐
missmisslulu1 天前
电容笔值得买吗?2024精选盘点推荐五大惊艳平替电容笔!
学习·ios·电脑·平板
GEEKVIP1 天前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
GEEKVIP1 天前
如何在 Windows 10 上恢复未保存/删除的 Word 文档
macos·ios·智能手机·电脑·word·笔记本电脑·iphone
奇客软件1 天前
iPhone使用技巧:如何恢复变砖的 iPhone 或 iPad
数码相机·macos·ios·电脑·笔记本电脑·iphone·ipad
奇客软件2 天前
如何从相机的记忆棒(存储卡)中恢复丢失照片
深度学习·数码相机·ios·智能手机·电脑·笔记本电脑·iphone
GEEKVIP2 天前
如何修复变砖的手机并恢复丢失的数据
macos·ios·智能手机·word·手机·笔记本电脑·iphone
一丝晨光2 天前
继承、Lambda、Objective-C和Swift
开发语言·macos·ios·objective-c·swift·继承·lambda
GEEKVIP3 天前
iPhone/iPad技巧:如何解锁锁定的 iPhone 或 iPad
windows·macos·ios·智能手机·笔记本电脑·iphone·ipad
KWMax3 天前
RxSwift系列(二)操作符
ios·swift·rxswift