使用 Swift 代码优化项目编译速度

news/2024/7/20 20:35:42 标签: swift, 开发语言, ios

引言

软件的性能是评价一个软件质量的重要指标,尤其在今天这个时代,性能已成为大型项目不可或缺的考虑因素之一。对于用户量极大的软件,如网银系统、在线购物商城等,更是必须保证其高效稳定的性能。在这种背景下,优化项目的编译速度就显得尤为重要。本文将介绍如何使用 Swift 代码优化项目编译速度。

找出编译耗时过长的文件

要优化项目的编译速度,首先需要把耗时过长的文件找出来,然后进行重点优化。这里会用到 Xcode build 的两个OTHER_SWIFT_FLAGS:

  • -Xfrontend:如果编译或类型检查时耗时多长,则在 Xcode 中输出警告。
  • -debug-time-function-bodies:输出每个函数的编译时长。

添加这些 flag 的方法为:

  1. 选中 Target
  2. 选中 Build Settings
  3. 搜索 “Other Swift Flags”
  4. 添加 -Xfrontend -debug-time-function-bodies

基于这两个 flag,有 3 个方法可以找到耗时过长的文件:

方法一:使用克魔助手

克魔助手是一款专为苹果手机 iOS 应用开发设计的辅助工具,提供了丰富的性能监控功能,帮助开发者优化应用的性能。以下是使用克魔助手找到编译耗时过长的文件的步骤:

  1. 下载克魔助手:用户可以前往克魔助手工具官网进行免费下载,该工具提供绿色软件版本,无需其他安装流程。下载后解压即可开始使用。下载地址是 https://www.keymob.com 。
    在这里插入图片描述

  2. 注册和登录:为了使用克魔助手工具,用户需要在电脑上安装并登录该工具。在登录后,用户可以继续其他操作流程。克魔开发助手提供了简单的登录码获取流程,确保用户能够方便地使用该工具。

在这里插入图片描述

3.选择文件管理界面并开始监听:双击克魔开发助手.exe 启动克魔助手后,点击右上角的登录按钮,输入邮箱后,没登录码的点击获取登录码,有的可以直接输入登录码,登录成功后,选择文件管理界面。然后自定义选择列,并点击 “开始监听” 来查看应用程序的性能情况。
在这里插入图片描述

方法二:使用 Xcode 控制台

在 Xcode 的控制台中输入以下命令即可输出时间最久的前 10 个文件:

find . -type f -name '*.swift' -exec \
  sh -c "echo '{}' && swiftc -v -c '{}' 2>&1 | awk '/^.{10}[ ]+[0-9\.]+ms/{print \$0}' | sort -rn | head -10" \;

方法三:使用 Xcode 插件

使用 Xcode 插件 SwiftLint 可以自动输出编译耗时最长的文件。安装方法如下:

  1. 打开 Terminal,输入以下命令:
brew install swiftlint
  1. 在 Xcode 中打开 Preferences(快捷键 Command + ,),选择 Text Editing,然后选择 Code completion。
  2. 在 Code completion 下面的 Fuzzy matching 一栏中,勾选 Show snippets using: 和 Swift。然后再选择 Edit All-in-One Snippet…。
  3. 进入 Snippet 编辑页面,复制以下代码并保存:
// MARK: - Performance Metrics

// Prints the compile time of each function or method in this file.
// Add to the `OTHER_SWIFT_FLAGS` build setting for the target.
// -Xfrontend -debug-time-function-bodies
//
// For more information about how to use debug-time-function-bodies see:
// - https://pspdfkit.com/blog/2018/how-to-reduce-swift-compile-times/
// - https://github.com/apple/swift/pull/13132#issuecomment-312358040
// - WWDC 2018 session 404 Optimizing Swift build times
// - https://youtu.be/nJwVabxL5Gw?t=11m16s
//
// If you add this to a Swift file, it will print the compile time of each
// method in this file to the console on build.
//
// Usage:
// In Xcode 9.x and later:
// 1. Open your project
// 2. Go to the Build Phases tab of your app's target
// 3. Click the + button in the top left and select "New Run Script Phase"
// 4. Add the following code to the script area below the shell:
//      "${PODS_ROOT}/SwiftLint/swiftlint" --no-cache --config "${PODS_ROOT}/SwiftLint/.swiftlint.yml"
//      "${PROJECT_DIR}/Scripts/perf.swift"
//    Note: You may need to customise the paths to suit your project structure.
// 5. Drag the new run script phase to be just before the "Compile Swift Sources"
//    phase in the list.
// 6. Rebuild your project (Command-B)
// 7. The compile time for each function in each source file will now be logged
//    to the console, sorted by longest compile time first.

import Foundation

let numBitsInByte = 8

extension Double {
    func rounded(toPlaces places: Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return (self * divisor).rounded() / divisor
    }
}

extension String {
    func padding(toLength length: Int, withPad padCharacter: Character) -> String {
        let padding = String(repeatElement(padCharacter, count: max(0, length - count)))
        return self + padding
    }
}

func readableTime(_ time: Double) -> String {
    if time < 0.001 {
        return "< 0.001ms"
    } else if time < 1 {
        return "\(time.rounded(toPlaces: 3))ms"
    } else {
        var timeStr = "\(time.rounded(toPlaces: 2))s"
        if time > 60 {
            let minutes = Int(time / 60)
            let seconds = time.truncatingRemainder(dividingBy: 60)
            timeStr = "\(minutes)m \(seconds.rounded(toPlaces: 2))s"
        }
        return timeStr.padding(toLength: 10, withPad: " ")
    }
}

func measure<A>(name: String, _ f: () -> A) -> A {
    let start = DispatchTime.now()
    let result = f()
    let end = DispatchTime.now()
    let time = Double(end.uptimeNanoseconds - start.uptimeNanoseconds) / Double(numBitsInByte * 1000000)
    print("\(readableTime(time)): \(name)")
    return result
}

  1. 在 Xcode 的 Build Phases 中添加一个 Run Script,将以下代码复制到 Run Script 中:
"${PODS_ROOT}/SwiftLint/swiftlint" --no-cache --config "${PODS_ROOT}/SwiftLint/.swiftlint.yml"
"${SRCROOT}/Scripts/perf.swift"

总结

优化项目的编译速度是一个不断迭代的过程,需要不断地寻找和解决问题。本文介绍了如何使用 Swift 代码来找出编译耗时过长的文件,并介绍了三种方法:使用克魔助手、使用 Xcode 控制台和使用 Xcode 插件 SwiftLint。希望这些方法能够帮助读者优化项目的编译速度。

参考资料

  • 克魔助手官网

http://www.niftyadmin.cn/n/5335793.html

相关文章

分布式ID(2):雪花算法生成ID

1 雪花算法简介 这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等,比如在snowflake中的64-bit分别表示如下图(图片来自网络)所示: 41-bit的时间可以表示(1L&l…

TypeScript语法总结

JavaScript 与 TypeScript 的区别 TypeScript 是 JavaScript 的超集&#xff0c;扩展了 JavaScript 的语法&#xff0c;因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改&#xff0c;TypeScript 通过类型注解提供编译时的静态类型检查。 TypeScript 可处理已…

Spring.Shell.History内置命令覆盖

文章目录 问题解决方案覆盖方法代码yaml配置&#xff1a;指定保存历史命令文件的路径 问题 最近工作上遇到的一个小问题&#xff0c;在Spring Shell中&#xff0c;我们可以自己定义一些命令&#xff0c;已完成我们想要的功能&#xff0c;也可以使用内置命令如help、history、c…

HBase学习五:运维排障

1、负载均衡 1.1 Rgion迁移 在当前的HBase版本中,Region迁移虽然是一个轻量级操作,但实现逻辑依然比较复杂,≈复杂性主要表现在两个方面:其一,Region迁移过程涉及多种状态的改变;其二,迁移过程中涉及Master、ZooKeeper(ZK)以及RegionServer等多个组件的相互协调。 …

MyBatis 使用报错:org.xml.sax.SAXParseException 元素内容必须由格式正确的字符数据或标记组成

文章目录 前言问题分析解决方案方案一&#xff1a;使用 CDATA 区块&#xff0c;依然使用 “ > ” 或者 “ < ”方案二&#xff1a;使用转义字符 个人简介 前言 今天在使用 MyBatis 时出现报错&#xff1a; Caused by: org.xml.sax.SAXParseException: 元素内容必须由格式…

“深入理解 Docker 和 Nacos 的单个部署与集成部署“

目录 引言&#xff1a;Docker Nacos 单个部署1.1 什么是 Docker&#xff1f;Docker 的概念和工作原理Docker 为什么受到广泛应用和认可 1.2 什么是 Nacos&#xff1f;Nacos 的核心功能和特点Nacos 在微服务架构中的作用 1.3 Docker 单个部署 Nacos Docker Nacos 集成部署总结&a…

c# 视频播放之Vlc.DotNet.Forms

先说下优缺点 优点&#xff1a;与电脑无关&#xff0c;能播放主流编码格式视频。 缺点&#xff1a;只能播放本地视频&#xff0c;网络视频播放不了。 下面是具体操作和代码 1. 安装Vlc.DotNet.Forms 和 VideoLAN.LibVLC.Windows Vlc.DotNet.Forms 是播放库&#xff0c;Vid…

我在代码随想录|写代码Day9之28. 实现 strStr(),459. 重复的子字符串,55. 右旋字符串(第八期模拟笔试)

博主介绍: 27dCnc 专题 : 数据结构帮助小白快速入门 28. 实现 strStr() 题目; 代码 1 class Solution { public: //KMPint strStr(string s, string t) {int n s.size(),mt.size();if(m0) return 0;s.insert(s.begin(), );t.insert(t.begin(), );vector<int> next(m1);…