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 […]

零件中的核心数据优化— 1

大多数时候,我们的应用程序都具有数据存储功能,例如缓存,提供脱机支持或提高应用程序性能等目的。 在本系列文章中,我们将探索一些设计技巧,并为提高iOS应用程序上的Core Data性能奠定基础。 这会导致iPad App的fps下降。 它不仅降低了fps速度,而且使我们的应用程序反复缓慢。 滚动tableview / collection视图确实很痛苦,因为App暂时停止了。 如果不运行Core Data工具,我将不会发现此问题。 规则1:测量,测量和测量 如果进行测量,您会发现板子前面有问题。 那么为什么不先这样做呢? 进行一些操作通常会导致我获取大量数据,因为我对记录中的每个项目都进行了重复的访存调用。 由于每个记录都可以使用其ID进行标识 您可以告诉CD根据ID一次获取所有记录。 编号:[Int] 让fetchRequest = NSFetchRequest (entityName:“ MyEntity”) fetchRequest.predicate = NSPredicate(格式:“ id IN%@”,id) 虽然它减少了我的提取次数,但仍然没有帮助我减少保存 算是因为我在做这样的傻事: 下载的记录中的ID { //在此更改托管对象的上下文并将其保存在context.perform { 做{ 尝试context.save() }将let错误捕获为NSError { fatalError(“错误:\(error.localizedDescription)”) } } } 由于Core Data将获取的对象保留在上下文中(在内存中),因此您可以修改存在于上下文中的获取的对象。 除非您清除上下文,否则上下文会保留MO的更改。 所以现在我们的代码看起来像: 下载的记录中的ID { //在此处更改托管对象的上下文。 updateEntity() //变更将在上下文中存在 } //现在保存上下文。 这会将更改从上下文推送到存储。 context.perform […]

iOS性能优化技巧

互联网上有太多关于“优化”的文章。 通过阅读这些文章,我一直在研究。 在这里,我想分享一些技巧,您可以从哪里开始优化应用程序。 调整点是; 触感 WebView中的触摸响应度 应用启动时间 减少影像资源 监控网络使用情况 在其他线程中解析Api响应数据 平滑滚动 因为我只想分享优化点,所以我不想附加详细代码或存储库。 触感 触摸响应度是用户由于输入而从设备获得反馈所花费的时间。 如果花费更长的时间,则意味着您的应用程序很笨拙。 要测量触摸响应时间,您可以测量从触发触摸事件到视图出现的时间。 然后,如何检测设备上的第一次触摸事件? 为此,制作一个名为MyApplication的自定义UIApplication来覆盖“ sendEvent:”。 // 。H 外部CFTimeInterval touchStartTime; // .m CFTimeInterval touchStartTime; @实现MyApplication -(void)sendEvent:(UIEvent *)event { touchStartTime = CACurrentMediaTime(); [super sendEvent:event]; } @结束 要应用自定义UIApplication,请转到“ main.m”并将“ MyApplication”放入“ UIApplicationMain”方法中。 #import“ AppDelegate.h” #import“ MyApplication.h” int main(int argc,char * argv []){ @autoreleasepool { 返回UIApplicationMain(argc,argv,@“ […]

更新IOS 11以升级您的移动服务

“ IOS 11无需担心” 智者 您是否更新过iOS? 如果不是,您可能生活在岩石下,这本身并不是一件坏事,但是如果您是应用程序所有者,则不是一件容易的事,因为您的应用程序用户很可能已经在那儿,并且手上有一颗炸弹 媒体在Internet上覆盖了iOS 11,但每天仍然弹出新信息,从用户和开发人员的反馈到关于如何使用新功能的疯狂(交叉)新想法。 在此博客中,我们希望重点关注系统更新对应用程序所有者的意义,因为自iOS 11发布以来,我们已经收到来自客户的大量优化应用程序产品的请求。 这是我们的简要摘要,可帮助您将挑战变成机遇。 1.应用内购买 对于那些业务与其应用程序直接同步的人来说,这是关键功能,正确使用它可以带来显着的销售增长。 下载应用程序并订阅其服务,只是为了查看其中提供哪些产品的想法,过去可能已经使您的潜在客户拒之门外。 借助此功能,他们可以直接在App Store中预览产品,甚至开始购买所需的商品,而不必下载应用程序本身。 现在,应用内购买会显示在产品页面上,并且可以显示在搜索结果中,也可以显示在“今日”,“游戏”和“应用”标签中。 如果您是应用程序所有者,请记住以下几点: 您可以在产品页面上一次选择最多促销20个应用内购买。 您可以根据业务需要随时更改显示在产品页面上的应用内购买,例如以限时优惠的产品为特色。 促进应用内购买并不能阻止人们下载您的应用,但实际上可以鼓励这样做。 如果用户未安装您的应用,但想购买推广的应用内购买,则他们会收到提示,要求您首先下载该应用。 直接在App Store中开始的交易,然后将继续在App中进行。 将您的用户转移到该应用后,最好立即显示付款单,以使购买过程变得简单,便捷。 任何消息传递或其他步骤可能会使您的潜在用户无法完成购买。 您可以使用SKProductStorePromotionController API选择用户在特定设备上看到的哪些促销应用内购买。 通过新设置,您可以隐藏用户在该设备上已经拥有的项目,或者根据用户以前的经验向用户显示产品的最相关版本。 查看StoreKit的新增功能以了解其工作原理。 最后,优化应用内购买商品在商店中的显示方式:确保您的应用宣传图片尺寸正确,显示名称易于用户理解并且不太通用,并且说明易于用户可以区分每次应用内购买的好处。 2.一般用户体验。 有四项重大的技术更改可以改善客户的用户体验。 第一个也是讨论最多的一个是,Apple已启用Siri,使其可以在iOS 11的第三方应用程序中使用。这意味着,您的用户将能够使用语音识别技术在您的应用程序中创建或更新各种服务。 除此之外,此版本的Siri在语言处理方面更为自然,这将帮助您改善移动服务的客户体验。 其次,Apple使用户可以在使用应用程序时禁用“评分和评论”通知。 乍一看,它可能是一个缺点,因为您需要找到获取反馈的新方法,但请考虑以下事实:它实际上有助于使您的用户更加沉浸于您的内容中,并使他们在应用程序上的体验不间断,因此更愉快。 第三个是Camera应用程序和存储格式的功能更改。 自上一个版本以来,Apple增强了媒体文件的压缩格式,该格式允许用户在iPhone上存储两倍的照片和视频。 此外,Apple在新相机中包括QR码阅读器和文档扫描功能。 过去,用户偏爱沉浸式内容,从而产生了对高质量图像,GIF和VR内容的需求。 新的存储格式将加速这一趋势。 换句话说,用户将能够使用iOS 11在您的服务中创建更多交互式内容。 第四个变化也是最有趣的变化是在ARkit的帮助下,新功能VR Flyover已添加到Apple Maps App中。 它的功能仍然有限,但是您已经可以体验该市的一些虚拟航班之旅。 如果您使用ARkit并且热衷于增强现实技术,则可以开发诸如Pokemon Go!之类的应用程序。 由于ARkit提供了空间感知能力,并为您的AR内容提供了平台,因此使用iPhone增强现实变得更加容易。 尽管如前所述,仍然存在局限性,但已经可以利用此功能在建筑,保健和其他行业以及游戏行业中积累经验。 3.应用服务推广 […]

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应用程序的二进制文件可能为数十兆甚至数百兆字节。 这么多的数据需要花费一些时间才能加载到内存中,这是隐藏的性能成本。 订单文件可加快将应用程序二进制文件加载到内存中的过程,从而提高整体性能。 要了解它们,我们首先必须看一下分页。 分页 操作系统将数据以页(即固定大小的块)(每个iPhone为16 KB)的大小加载到内存中。 每当调用一个函数或从二进制文件访问一条数据时,操作系统就会加载包含该函数的页面。 即使该功能仅占用页面的一小部分,操作系统仍将加载整个页面。 因此,如果存在碎片,即一起调用的函数驻留在许多不同的页面中,则将有加载页面的开销,将它们保存在内存中。 订单文件可以减少碎片。 什么是订单文件? 顺序文件是提供给链接器的文件,用于指定应将所有函数和数据放入二进制文件中的顺序。 如果可以将通常一起调用的功能(例如,所有在启动时调用的功能)组合在一起,则可以提高应用程序的性能。 注意:仅当您选择了所有性能低下的水果后,才能处理订单文件。 这是一个更为复杂的优化,无法保证您将获得多少加速。 确定应该是什么顺序 总览 排序的一种好方法是在第一次调用每个函数时。 因此,它可能以main开头,然后是-[AppDelegate applicationDidFinishLaunching:…]等。为此,我们可以使用coverage sanitizer ,这是一个编译器功能,其中每个被编译的函数都会在每次运行时调用全局处理程序。 然后,第一次使用任何特定功能调用处理程序时,我们会将其记录在列表中,然后将该列表写到文件中。 使用Coverage消毒器进行编译 在您的Xcode构建设置中,在“其他C标志”下添加-fsanitize-coverage=func,trace-pc-guard 。 如果您使用的是Swift,请在“其他Swift标志”下添加-sanitize-coverage=func并打开地址清理器(可以在方案设置中完成)。 对于要链接到主二进制文件的所有内容,请确保包括这些标志,例如Cocoapods。 在运行时记录 将此代码和此标头插入您的应用程序。 然后,尽可能多地使用该应用程序,并逐一浏览功能,从最受欢迎的功能开始到最受欢迎的功能结束。 最后,调用CLRCollectCalls() ,它将返回被调用函数的列表。 将此列表写到文件中,每个调用都单独行,然后将“ Order file”构建设置更改为该文件的路径。 然后,再次构建项目,并通过将列表与nm -j -p 比较,来验证它是否已重新排序。 两者应该匹配。 结论 订单文件可以减少内存消耗和CPU时间。 目前,它对于您的应用可能不是必需的或无用的,但它是您可以在需要时使用的另一种工具。 本文仅介绍如何在二进制文件中排序函数,但是如果有人要求,我也可以讨论如何在二进制文件中排序数据(例如,常量字符串)。

如何提高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”项目中的一些摘录: 在后台解码图像 : 您可以添加一些进一步的缓存控制以提高效率。 […]

Swift,C,LLVM编译器优化

用很少和基本的词来说,LLVM是一个编译器框架,在“前端”-“后端”多层体系结构中支持许多不同的编程语言,其中,第一层非常容易地对源代码进行解析和分类,以生成中间语言表示形式,第二层层将中间表示形式转换为针对不同处理器体系结构优化的实际组装机器代码。 当然,LLVM比这个简单的描述要多得多,但是我并不十分在意这篇文章中的LLVM。 我在这里真正关心的是专注于基于LLVM架构的Swift和Clang现代编译器如何进行编译,尤其是优化我们开发人员每天生成的源代码,尤其是这些编译器如何对某些旧式技巧,窍门做出反应和优化,我们尝试在源代码中花费一些时间。 在这篇文章中,我将测试一个在Swift和C中使用不同编程技术实现的超简单但繁琐的函数,以试图迫使编译器遵循一些经典的优化模式。 我将提供编译后代码的运行时执行性能结果,并分享生成的汇编代码中的一些优化细节。 假设您已经分配了一个很大的缓冲区,不管是在堆还是在堆栈上,我们都不在乎,我们可以很容易地说一个整数数组,我们的基本函数只需要为该数组的每个位置分配一个特定的值。 而已! 因此,在C语言中,我们的功能可能是这样的超级基本的东西: void testLoop(int64_t * buffer,int64_t tot){ for(int64_t i = 0; i <tot; i ++){ *缓冲区++ = 1; } } 在Swift中,类似的东西非常类似: func testLoop(_ a:inout [Int],_ tot:Int){ 对于i in 0 .. <tot { a [i] = 1 } } 注意,我在这里使用64位整数,因为这是64位体系结构上Swift Int的默认值,我希望能够支持很大的缓冲区以及巨大的循环。 一个好的开发人员通常可以在这种超级简单的场景中应用的基本技巧之一就是试图减少循环指令占用空间的影响。 举例来说,除了让循环具有n个交互并在每个循环交互上没有一条赋值指令,我们还可以将总的循环交互减少一个数量级,并在循环周期内放入10个这样的嵌套指令, 在C中: void testLoop(int64_t * buffer,int64_t tot){ int64_t […]

了解Swift写时复制机制

在Swift中,我们有引用类型(类)和值类型(结构,元组,枚举)。 值类型具有复制语义。 这意味着,如果您为变量分配值类型或将其作为参数传递给函数(除非它是inout参数),则将复制该值的基础数据。 您将拥有两个具有相同内容的值,但是分配在两个不同的内存地址中。 有关Apple博客上引用类型和值类型之间差异的更详细说明。 由于我们将要讨论写时复制,因此了解Swift值语义非常重要。 所以……开始吧 什么是写时复制? 在Swift中,当您具有较大的值类型并且必须将参数分配或作为参数传递给函数时,就性能而言,将其复制可能会非常昂贵,因为您必须将所有基础数​​据复制到内存中的另一个位置。 为了将问题最小化,Swift Standard库为某些值类型(例如Array)实现了这套机制,其中值仅在发生突变时才复制,即使在该值具有多个引用的情况下也才复制,因为如果该值是唯一引用的,不需要复制,可以在引用上进行更改。 因此,仅分配给变量或将Array传递给函数并不一定意味着它将被复制,并且确实可以提高性能。 真正重要的是要知道的是… 写时复制不是值类型的默认行为,它是在Swift标准库中针对某些类型(例如数组和集合)实施的。 因此,这意味着并非标准库中的每个值类型都具有此行为。 此外,除非您自己实现它,否则您创建的值类型没有它。 这是我将在下一节稍后讨论的内容。 让我们在实践中看一个例子: 这就是本文的全部,希望您喜欢🙂 如果您有任何意见或疑问,请告诉我。 我很高兴收到您的反馈feedback 您可以在Twitter上@ LucianoPassos11找到我。 感谢您阅读🙂

权力游戏

如果我们将应用程序开发与电影制作进行比较,那么主要的因素就是漂亮的UI和出色的用户体验(UX)。 就像电影制作一样,有一些工作人员在幕后工作,努力使我们的主角看起来比最好的演员更好。 在应用程序世界中,一些主要的后台工作人员具有响应式UI,可优化网络使用并减少电池消耗。 电池是所有智能手机用户的最大痛点。 如今,用户已经学会了如何节省智能手机的电池。 iOS会就如何利用资源和尽可能高效地运行代码做出明智的决定。 但是,在开发具有精美动画的应用程序或在紧迫的时间范围内工作时,我们经常忘记关注这些因素,而且显然会给UX造成巨大损失。 或者,用户将停止授予您访问位置,后台活动等的权限。同样,您的应用中用户体验也不佳。 能耗过多的罪魁祸首是CPU,网络操作,位置和运动更新,蓝牙。 无论我们是播放视频还是只是在UI上进行任何更新,任何东西都会耗尽电池。 我们可以通过许多实践为平台的整体能源效率做出贡献。 让我们一一研究。 背景活动 应用程序应在后台尽可能少地工作,无论何时,我们都应在完成任务后通知系统。 系统对任务进行优先级排序,我们应该通过为NSOperation,NSOperationQueue,NSThread和调度队列提供正确的优先级来帮助完成任务。 我们应该减少计时器的使用。 我们可以使用事件通知或GCD工具进行同步。 如果必须使用计时器,那么我们应该最大化时间间隔,并在完成后使其无效。 文件操作也应最小化。 如果一个人需要频繁交易,则应该选择一个数据库。 用户界面 每个UI更新都需要CPU,GPU,当然还需要活动屏幕。 我们应该尝试减少视图数量,使用不透明度和模糊。 我们应该使用较低且一致的帧速率进行UI更新。 应避免在全屏视频上添加任何图层(例如,用于控制视频回报的元素),否则当用户不与之交互时,我们可以尝试删除这些图层。 我们应该使用较深的颜色,因为较亮的颜色需要更高的能量才能显示。 我们应保持较小的介质尺寸。 联网 批处理是网络运营的极乐。 我们应该尝试分批处理并减少这些操作。 我们还可以通过压缩最小化数据大小,避免冗余传输,缓存数据并使用可恢复传输。 信号强度也很重要。 不良的信号和低带宽会耗尽电池电量。 我们不应过度使用推送通知。 尝试使用延迟的交付方法而不是立即交付优先级来帮助系统优化性能。 可能的替代方法是根据您的用例的本地通知。 VoIP应用程序可以使用PushKit框架而不是持久连接。 当出现VoIP时,PushKit会唤醒设备,而持久连接会继续发送消息以使它保持活动状态,即使呼叫未激活也是如此。 运动 如果不是必须要做的事情,请避免连续运动更新。 尝试指定较高的更新时间间隔。 不正确和不必要的位置使用可能会阻止设备进入休眠状态,并使位置硬件通电。 请求位置,使用它并停止位置服务。 我们可以降低标准位置更新的准确性,并在准确性不符合预期的情况下停止位置更新。 在后台运行时,我们应该推迟位置更新。 当我们需要特定位置的进入和退出通知时,请使用区域和信标监视。 此外,当GPS级别的精度对于操作而言不是很关键时,我们可以注册进行重大更改的位置更新,而不是连续更新。 外部设备 在与蓝牙设备进行交互时,我们应格外小心,因为它在两个设备上都消耗能量。 我们应该在需要时扫描蓝牙设备。 我们应该最小化所有设备的处理。 尝试查找特定的(必需的)服务和特征。 我们应尽量减少智能手表和手机之间的流量,因为它会影响两个设备的电池。 苹果推出了Watch Connectivity […]