Tag: 性能

在Xcode 10中启用新添加的选择加入功能

在WWDC 2018期间,Apple宣布了具有许多新功能的Xcode 10。 其中的许多功能会自动为您提供并默认启用,但其中一些功能可能不会显示,需要进行一些手动调整。 代码折叠 要启用它,请在“ Text Editing > Editing下打开首选项,然后选择Code folding ribbon 。 增量构建 在其他年份中,我们当中许多人可能会使用“ Whole Module编译模式来缩短构建时间。 正如苹果在博客上告诉我们的那样: 全模块优化是Swift编译器的优化模式。 整个模块优化的性能胜利在很大程度上取决于项目,但是它可能高达两倍甚至五倍。 建议今年,我​​们建议不要隐式使用“ Whole Module编译模式,而应使用“ Incremental以获得更好的结果。 默认情况下,应在Xcode 10中启用此功能,但您可能需要在项目中进行验证。 正如Apple在“ Swift的新功能”会议中提到的那样: 使用 整个模块 进行 调试 构建是改进构建的权宜之计。 整个模块 可防止增量构建。 定义正确的优化级别 自Swift 4.1起可用,有一个新的优化模式可用,该模式可以进行专门的优化以减小代码大小。 更深入的细节可以在Swift博客文章Swift 4.1中的代码大小优化模式中阅读。 提高测试性能 Xcode 10引入了许多与测试性能有关的改进。 单元测试和UI测试的完成速度都比过去快得多。 通过打开测试方案设置,可以启用三个新选项: Execute in parallel on Simulator 。 这将在多个模拟器上并行运行UI和单元测试,并大大加快测试速度。 Randomize execution order […]

在iPhone上清除历史记录的有效方法

清除iPhone中的历史记录是提高性能和个人隐私的好习惯。 通话记录,浏览记录,消息记录等。 在本文中,我将指导您如何清除iPhone中的所有历史记录。 清除通话记录 打开您的手机应用程序,然后选择标签“最近”。 标签“编辑”,它将出现呼叫记录。 然后,点击“清除”以删除所有通话记录。 2.清除消息历史记录 信息很重要,有时您需要删除信息以保护个人隐私。 有时您需要保存您的消息。 因此,在这种情况下,请考虑是否应该删除或保存。 这是您自己的选择。 转到消息应用程序,然后选择“编辑”。 选择要删除的保护,然后选择“删除”。 如果要自动清除消息历史记录,可以更改这些设置。 转到“设置”,然后选择“消息”。 然后,选择“保留消息”,然后选择要保留消息的时间。 我建议您选择30天。 3.清除键盘历史记录 转到设置,然后选择“常规”标签。 标签“重置”,它将显示重置选项。 选项卡“重置键盘字典”,然后将要求您确认。 此设置将删除您保存的自定义单词。 4.清除Safari浏览历史记录 此设置将删除Safari浏览器中保存的所有信息或cookie。 转到设置并标签“ Safari”。 然后,点击“清除历史记录和网站数据”。 将出现确认面板,并显示“清除历史记录和数据”选项卡。 现在,所有的cookie,浏览历史记录,缓存和自动填充信息将被删除。 此效果将反映在您使用自己的iCloud帐户登录的任何Apple设备上。 5.清除Google搜索记录 使用Google搜索服务的最简单方法是使用Google搜索应用。 大多数用户不会在其浏览器中使用Google搜索,而是通常与Google Search App一起使用。 如果您在iPhone中使用Google搜索应用,则需要清除浏览历史记录。 在iPhone中打开您的Google应用,然后点击“设置”。 标签“隐私。 标签“浏览”选项,然后将出现“历史记录”部分页面。 标签“清除设备上的历史记录。 备注:此设置只会删除您iPhone上的搜索历史记录。 它不会在Google帐户上删除。 您的搜索记录仍保存在Google帐户中。 6.清除所有数据 此选项将删除iPhone中的所有历史记录和数据。 要注意自己。 转到设置并标签“常规”。 标签“重置”选项,然后标签“清除所有内容和设置”。 请稍等片刻以重置您的iPhone。 重置完成后,您必须选择初始设置。 您可以设置为新iPhone,从iCloud备份还原,以及从iTunes备份还原。 这是您自己的选择。 如果必须将iPhone保留为出厂设置,建议您将其设置为新的iPhone选项。 结论 […]

Swift数组vs ContiguousArray

我们都每天使用数组。 但是我们是否考虑过有效使用它们? 在这里,我将讨论一种技术,通过该技术,我们可以基于其中的Element改善数组的性能。 数组–理想元素 尝试在数组中使用值类型。 使用值类型时,优化器可以消除Array中大部分的开销,这些开销是处理数组支持NSArray的可能性所必需的。 通过使用没有引用类型的值类型,可以避免额外的保留,释放Array内部的流量。 但是要小心并考虑在使用大值类型与引用类型之间进行权衡。 您可以在此处了解更多信息。 ContiguousArray ContiguousArray类型是一种特殊的数组,始终将其元素存储在内存的连续区域中。 如果数组的Element类型是类或@objc协议,并且您不需要将数组桥接到NSArray或将数组传递给Objective-C API,则使用ContiguousArray可能比Array效率更高,并且具有可预测的性能。 如果数组的Element类型是结构或枚举,则Array和ContiguousArray的效率应相似。 考虑以下课程。 班级地址{ var street =“” var city =“” var state =“”; 枚举AddressAttributes { 凯斯街 凯斯城 案件状态 } func updateAttribute(值:字符串,属性:AddressAttributes){ 开关属性{ case.Street: 街道=价值; 案例城市: 城市=价值; 大小写 状态=值; } } } 我测量了将此类对象添加到Array和ContiguousArray所需的平均时间。 我采用了一个任意值(1000000),只是为了演示如何在更大范围内表现不同。 func testPerformanceForClassArray(){ 让地址=地址() var数组:[地址] = [] 自我衡量{ for _ in […]

铬网络

我们的iOS应用程序的网络堆栈最近已切换为Chromium网络堆栈。 其背后的关键原因是我们希望在iOS和Android之间共享代码。 其他 主要原因包括: 可以访问较低级别的网络堆栈以进行优化和报告,并避免系统库中的错误 能够打开/关闭功能。 SDCH / Brotli / SPDY / H2 / QUIC / IPv6支持。 同步和异步联网API。 集成新网络堆栈的最简单方法是拦截NSURLProtocol并通过Chromium堆栈处理请求。 在理想的情况下,我们希望抽象出NSURLSession层并轻松切换到Chromium网络堆栈。 需要注意的 几点 : 框架大小。 该框架需要仔细剥离以减小二进制大小。 (例如,由于H2不在,因此无需支持SPDY) 守卫。 获取门禁的请求应通过原始网络堆栈。 关闭URLCache。 禁用内部cookie处理,以使cookie具有与其他堆栈/ webview同步的统一存储。 Chromium网络堆栈设计文档 下面是一个简短的摘要: 主要接口是URLRequest和URLRequestContext ,前者表示URL,后者包含满足URL请求的上下文,包括cookie,主机解析器,代理解析器,http缓存等。 网络请求 剖析 启动URLRequest时,首先决定要创建哪种URLRequestJob 。 您可以通过URLRequest::Interceptor和URLRequest::ProtocolFactory定制请求。 URLRequestHttpJob查询CookieMonster以标识cookie并随后创建一个HttpTransaction 。 该事务将首先检查HttpCache ,如果未命中,我们将创建一个HttpNetworkTransaction来处理请求。 事务被提供给HttpNetworkSession以包含执行HTTP请求的上下文状态。 HttpNetworkTransaction要求HttpStreamFactory创建HttpStream 。 工厂返回一个HttpStreamRequest并处理如何建立连接的所有逻辑。 建立连接后,将包装直接HttpStream与网络对话的HttpStream子类。 HttpStreamFactory进行代理解析,以确定是否需要代理。 端点将检查SpySession中是否有可用的SpdySessionPool. 连接管理 套接字池从实现中提取套接字请求,从而使我们对套接字进行“后期绑定”。 套接字请求可以通过新连接的套接字或空闲的套接字来实现(重用以前的http事务) 支持的仪器 […]

我们如何解析BSON不会产生开销性能

BSON是一个鲜为人知的图书馆,经常使用。 它是MongoKitten的核心,并且BSON规范一直被所有MongoDB用户使用。 我们开发了一个BSON库,它通过利用规范细节和我们能想到的每一个技巧,都胜过其他所有库。 序列化 在我们的BSON库中,序列化几乎不影响性能。 俩? 对于每种可能的操作,我们创建了一种专门执行该操作的专门算法。 两个操作可能共享相同的基本元数据要求,例如元素的位置。 为此,我们保留了文档中所有元素元数据的缓存。 这样,当一个操作第一次遇到一个元素时,其他操作就不需要花费时间了。 这样,我们可以高效地进行解析,并始终保持所有数据序列化。 这也意味着我们绝不会反序列化甚至读取不需要的数据。 这样可以节省CPU性能,内存副本和内存使用率,这是该库独有的。 利用规范 BSON的规范(http://bsonspec.org)具有始终位于消息核心的元素。 文献。 文档从Int32的整个长度开始,以空终止符结束。 规范中存储了长度和空终止符的原因是为了提高解析性能。 BSON可以递归嵌套文档。 因此,如果您想跳到同一级别的下一个元素,则这两个属性可以提高解析性能。 但是,如果要将元素添加到文档,则需要删除null终止符,添加该元素,然后再次添加null终止符。 并且在文档的内容更改之后,将执行其他操作以更新文档的长度。 这是没有问题的,直到您意识到此时添加5个属性会花费15个额外的堆操作。 而且堆非常昂贵。 因此,我们从顶级文档的内部存储中删除了Int32和null终止符。 这使这些操作的成本降低了四倍。 解析/提取 BSON的数据始终是序列化的,因此提取需要即时进行。 我们通过懒惰地搜索和反序列化文档中的信息来做到这一点。 在您要求我们提供某些信息之前,我们不知道文件的内容。 届时,我们将有效地解析文档,直到找到所需的信息。 这样,我们解析的内容不会超出我们的需要。 { “ username”:“ Joannis”, “年龄”:21岁, “男”:是的, “ admin”:是的, “权限”:[“全部”,“更多”,“无限”] } 如果您要访问键“用户名”,则将仅查看和缓存此“用户名”键,因为它是文档中的第一个实体。 不会扫描,缓存或查看“年龄”,“男性”,“管理员”和“权限”。 现在,当您访问male ,解析器将在username之后恢复并找到age而不反序列化值。 接下来,找到male ,将其击中,反序列化该值,停止扫描并返回该值。 现在,如果您请求age ,它已经知道age在哪里并反序列化此信息。 如果您寻找nonexistingkey ,它将一直扫描直到permissions不匹配为止,并将顶级文档标记为“完全扫描”,因此无需再次扫描。 防止将来无用的扫描无法阅读文档末尾。 如果由于某种原因您需要访问权限的第二个[1]属性,它根本不会提取permissions文档。 而是以递归的方式开始扫描permissions内的值,就像使用顶级文档一样。 […]

建立有效的布局

关于iOS,我们大多数人已经使用AutoLayout在UI中定位内容已有相当长的时间了。 但是我们是否曾经考虑过有效使用它,或者您多么容易使UI变得如此复杂而导致丢失帧。 当我们以编程方式添加约束时,这更适用。 渲染循环 大多数应用的目标帧率为60 FPS,相当于每帧16.67毫秒。 渲染循环是每秒可能运行120次的过程。 这样可以确保所有内容都准备好用于每个帧。 渲染循环分为三个阶段。 1.计算约束 从叶的大多数视图一直到窗口的视图层次结构。 2.布局视图 从窗户向下朝树叶开始,这是相反的方向。 3.显示/绘制 这也从窗口开始朝着叶子的方向相反。 避免约束搅动 当您不必要地更新约束但并非所有子视图都需要重新渲染时,就会发生搅动。 这将为布局引擎增加其他工作,从而导致渲染循环中花费更多时间。 下面的示例演示如何避免使用非常简单的方法重新计算静态约束。 激活约束 激活约束后,将创建一个方程式,布局引擎将对其求解以获取minX,minY,宽度和高度。 在布局阶段,此帧数据将从布局引擎提供给视图,并且将相应调整每个视图的大小和位置。 对于具有静态位置的视图,而不是激活停用一组约束的方法,请尝试查找是否可以使用setHidden和hide / show以避免布局引擎和布局阶段的额外开销。 内在内容大小 具有非视图内容的视图将基于该非视图内容返回其固有内容大小的大小。 这方面的两个示例是UIImageView和UILabel,UIImageView使用其图像的大小来计算其内部内容的大小,UILabel测量其文本并使用其返回其内部内容的大小。 这用于创建大小约束。 文本测量可能很昂贵。 因此,如果您的应用程序是文本密集型应用程序,并且如果您知道文本所需的大小而无需进行所有文本度量,那么您可以返回该大小和固有内容大小,或者如果您打算放置此视图在屏幕上,无论其中的文本大小如何,约束都将完全定义大小。 例如,约束总是会使它大于您所拥有的文本量。 systemLayoutSizeFittingSize 这用于从布局引擎获取尺寸信息。 尝试将其使用量降到最低,尤其是在表格或集合单元格内部,因为这可能会对滚动性能产生不利影响。 调用此方法将创建一个布局引擎,并将约束添加到此引擎,解决布局,然后返回顶视图框架的大小,然后丢弃该引擎。 因此,总的来说,性能影响是线性的,取决于您添加的约束。 约束越复杂,求解这些方程式以及渲染循环中的后续阶段所花费的时间就越多。 布局引擎是一个缓存和一个依赖项跟踪器,因此已经解决的值将存在于缓存中,并且相对于此添加新约束将很快。 设置其他参数(例如约束优先级)将花费更多时间来计算,建议除非您确实需要它们,否则不要过多使用它。

如何提高iOS应用的性能

基础 在开始建议之前,最好先定义并阐明本文之外的基本概念,这是主要主题 。 您可能已经知道,主线程不应用于繁重的操作,而应主要用于: 接受用户输入/交互; 显示结果并更新UI。 当主线程必须处理太多操作时,最常见的后果是丢帧现象,这是很普遍的现象,当我们不能保证60 fps(或每16.67毫秒一次)时,就会发生这种情况。 如何调试和识别精确丢失的帧? 有时,很容易发现它们,因为最关键的问题是不响应 ,而其他时候则不是,我们需要更准确的信息来跟踪它们。 例如,使用CADisplayLink (以非常快速的方式直接通过代码跟踪它们)或使用TimeProfiler以更准确的方式进行跟踪 。 要使用CADisplayLink,您可以简单地使用此类: 现在您知道您的帧下降了,该怎么办? 您可以采取一些措施,在本文中,我建议一些措施: 减少视图和透明视图的数量 最小化在连续调用的函数中完成的工作量 解码JPEG图像 屏幕外渲染 让我们一一讨论。 1.减少视图和透明视图的数量 为了提高应用程序的性能,要做的第一件事是(尽可能): 减少视图数量; 避免透明。 解决第二点很简单: label.layer.opacity = 1.0 label.backgroundColor = .white 为了轻松发现透明胶片的这种重叠,我们可以依靠一个非常方便的工具:调试->视图调试->渲染-> 颜色混合层 。 该工具使我们可以轻松地发现视图重叠,如以下示例所示: 2.最小化连续调用函数中完成的工作量 似乎很明显,但是像cellForItemAt indexPath或scrollViewDidScroll之类的函数必须非常快,因为它们是连续调用的。 始终确保使用最轻巧的配置方法来拥有“最哑”的视图/单元。 (例如,不涉及布局约束,对象分配等) 3.解码JPEG图像 当我们处理掉帧问题时,“通常的嫌疑人”之一就是图像解码。 通常,此操作是在主线程下通过imageViews完成的。 但这有时会导致我们的应用程序持续减速,尤其是在图像很大时。 为了减轻该问题,一种解决方案是将解码工作移至后台队列 。 这样,操作将不会像UIImageView所采用的常规解码那样高效,但是mainThread将是免费的。 下面让我们看一下卢克·帕罕(Luke Parham)的“ Catstagram”项目中的一些摘录: 在后台解码图像 : 您可以添加一些进一步的缓存控制以提高效率。 […]

在Xcode 10中进行性能分析

Xcode 10提供了分析构建性能的新方法。 使用新的“构建时间摘要”收集对构建性能的宝贵见解。 使用“构建时间摘要”构建性能见解 Xcode 10中的新增功能是“使用时序摘要生成”操作。 运行此操作将构建您的项目,该项目一旦显示了构建摘要,就可以使用“ Product > Perform Action > Build with Timing Summary或使用xcodebuild -buildWithTimingSummary在菜单中进行触发。 构建完成后,导航至“报告导航器”,然后选择最后一个构建。 一直向下滚动,直到看到“ Build Timing Summary”。 这是研究应该在哪里改进项目的一个很好的起点。 通常大部分时间都是CompileSwiftSources和PhaseScriptExecution 。 第一个显然归结于您的Swift代码。 后者指向您的自定义构建阶段。 通常可能会禁用某些运行脚本,而这些仅是发行版本所必需的。 改善构建性能 尽管这篇文章专注于分析构建性能,并且有很多方法可以提高构建性能,但是Xcode中有自己的设置可以直接提高性能。 使用 整个模块 进行 调试 构建是改进构建的权宜之计。 整个模块 可防止增量构建。 其中之一是启用Incremental Builds而不是Whole Module编译。 在“我在Xcode 10中启用新添加的选择功能”中阅读有关此内容的更多信息。 这个故事最初发布在: https://www.avanderlee.com/optimization/analysing-build-performance-xcode-10/

Swift的竞争性编程

最初发布于 swiftrocks.com 。 竞争编程是掌握特定编程语言的一种好方法。 即使您对参加诸如Facebook Hacker Cup之类的世界大赛不感兴趣,仅使用语言的基础知识来解决棘手的算法问题,也会使您面临该语言所没有的方面/捷径,例如效率某些方法/操作以及如何编写更好的替代方法。 这是一个很酷的爱好,而且,作为奖励,您甚至可以间接地为自己备受恐惧的Big 4采访做好准备,在这些采访中您必须在白板上解决算法问题! 尽管在真正的竞争中,使用Swift编码会造成很大的麻烦(因为与其他语言相比,它有点慢,并且几乎没有本地数据结构),但是许多流行的在线平台(如LeetCode,HackerRank和Codefights)都支持Swift,它们是一种很好的方式以使自己成为更好的iOS开发人员,特别是因为竞争问题只会接受非常快速的算法作为可能的解决方案。 如果您以前从未这样做过,我强烈建议您尝试一下。 在本文中,我将为您提供有关如何使用Swift读取输入数据的简短教程,以及一些解决Swift中竞争问题的技巧。 使用Swift读取标准输入 在竞争性编程中,问题的输入通常被馈送到命令行应用程序,该命令程序对此有所了解并输出所需的结果。 诸如LeetCode和CodeFights之类的平台将自动为您处理输入数据,并公开一个空的Swift方法,该方法应返回问题的解决方案,但是其他平台(如HackerRank)有时会让您手动读取,解析标准输入然后打印结果。 幸运的是,这并不像听起来那样复杂。 要模拟竞争性编程环境,请在Xcode中创建一个命令行工具项目: 请注意,命令行工具不是Cocoa应用程序,因此您将无法访问UIKit东西! 像Foundation这样的核心框架就在这里。 在main.swift ,键入并运行以下代码: let line = readLine() print(“Got something! \(line)”) 此时,程序将被冻结。 readLine()是一种标准库方法,可以同步读取标准输入并返回String? 一旦检索到整行,或者如果达到EOF,则返回nil 。 如果您在Xcode的控制台中键入内容,程序将继续执行并打印您编写的内容: 但是,竞争性编程问题可能需要数百行输入。 您可以使用while循环使代码运行直到输入结束: while let line = readLine() { print(“Got something! \(line)”) } 这就是您开始需要了解的所有信息。 从现在开始,您使用纯Swift的技能是唯一的变量。 如果您以前从未这样做过,这是一个示例问题: 示例问题 给定一个整数数组,找到其元素的总和。 输入格式 第一行包含一个整数,表示数组的大小。 第二行包含n空格分隔的整数,它们表示数组的元素。 输出格式 将数组元素的总和打印为单个整数。 […]

在Swift中创建不可变的委托

最初发布于 swiftrocks.com 。 为了防止诸如委托之类的属性发生引用循环,通常使用weak关键字: weak var delegate: HomeViewDelegate? 不幸的是,由于它可以保护您避免丢失引用,因此weak关键字会强制使用var和可选类型,如果您要构建的UIView类的东西在没有委托的情况下不能使用,那么这可能会非常麻烦。突然减少变更代表: class HomeView: UIView { weak var delegate: HomeViewDelegate? func renderView() { guard let delegate = delegate else { //Timmy: this should never happen! return } let category = delegate.currentlySelectedCategory() categoryView.render(category: category) delegate.homeViewDidUpdate() } } 但是, weak不是打破参考周期的唯一方法。 就像在捕获列表中一样,关键字unowned可以在属性中使用以创建非强引用: unowned let delegate: HomeViewModelDelegate 与weak引用不同, unowned引用应始终具有价值。 这样,您不仅可以在声明非可选类型时使用它们,而且还可以通过let来使用它们,从而恢复不变性并确保您的对象不会以意外的方式起作用: class HomeView: […]