内容简介:作者:Mattt,译者:在 Web 的世界里,速度不是一种奢求;它事关生死。
作者:Mattt, 原文链接 ,原文日期:2018-08-26
译者: 雨谨 ;校对: wongzigii , numbbbbb ;定稿: Forelax
在 Web 的世界里,速度不是一种奢求;它事关生死。
近年来的用户研究表明,页面加载中 _任何_ 可以察觉到的延迟 —— 即大于 400 毫秒(字面意义上的“一眨眼的功夫”) —— 都会对转化率和参与率产生负面影响。网页加载时每多花一秒,就会多 10% 的用户返回或者关闭这个页面。
对于谷歌、亚马逊和 Netflix 这样的大型的互联网公司而言,这里和那里额外的一秒钟可能意味着年收入里的 数十亿 美金。所以那些公司投入如此多的工程努力来让网页更快,也没有什么奇怪的了。
有很多加速网络请求的技术:压缩和流技术、缓存和预加载、连接池和多路复用、延迟和后台运行。然而,还有一种比它们优先级更高,效果更好的优化策略: 不要在刚开始的地方发送请求 。
在这个方面,App 凭借先下载后使用的特点,拥有传统网页所不具备的独特优势。在这一周的 NSHipster 里,我们将展示如何以一种非传统的方式使用 Asset Catalog 来改善你的 App 的首次启动体验。
Asset Catalog 允许你根据当前设备的特点来组织资源文件。对于一个给定的图片,你可以根据设备(iPhone、iPad、Apple Watch、Apple TV、Mac)、屏幕分辨率( @2x
/ @3x
)或者色域(sRGB / P3),提供不同的文件。对于其他类型的 asset,你可能根据可用内存或者 Metal 版本的不同而提供不同的文件。请求 asset 时仅需提供名字,最合适的那个资源就会自动返回。
除了提供更简便的 API,Asset Catalog 还允许 App 使用 App 瘦身 为每个用户设备提供一个经过优化的更小的安装包。
图片是最常见的 Asset 类型,但是从 iOS 9 和 macOS El Capitan 开始,JSON、XML 和其他数据文件之类的资源也可以通过 NSDataAsset
加入到这种乐趣中。
如何使用 Asset Catalog 存储和获取数据
举个例子,让我们想象一个用于创建数字调色板的 iOS App。
为了区分不同深浅的灰色,我们可能会加载一个颜色和对应名字的列表。通常情况下,我们可能会在第一次启动时从服务器下载这个列表,但是如果恶劣的网络环境限制了 App 的功能,就会导致很差的用户体验。既然它是一个相对静态的数据集,为什么不以一种 Asset Catalog 形式将它添加到 app bundle 中?
步骤 1:向 Asset Catalog 中添加 New Data Set
当你在 Xcode 中新建一个 app 项目时,它会自动生成一个 Asset Catalog。在项目导航(Project navigator)中选中 Assets.xcassets
,打开 Asset Catalog 编辑器。点击左下方的 + 图标,然后选择 “New Data Set”。
这样会在 Assets.xcassets
下新建一个后缀名为 .dataset
的子目录。
默认情况下,Finder (访达)把这两种 bundle 都当做目录,以便在需要时查看和修改它们的内容。
步骤2:添加数据文件
打开 Finder,找到数据文件,把它拖拽到 Xcode 中 data set asset 的空白处。
当你这么做时,Xcode 会把那个文件复制到 .dataset
子目录,并将它的文件名和 通用类型标识符(Universal Type Identifier) 更新到 contents.json
元数据文件。
{ "info": { "version": 1, "author": "xcode" }, "data": [ { "idiom": "universal", "filename": "colors.json", "universal-type-identifier": "public.json" } ] }
步骤3:使用 NSDataAsset 访问数据
现在你可以使用如下代码访问文件的数据:
guard let asset = NSDataAsset(name: "NamedColors") else { fatalError("Missing data asset: NamedColors") } let data = asset.data
对于我们颜色 App,我们可能在一个 view controller 的 viewDidLoad()
方法中调用上面的代码,然后解码返回的数据,获取 model 对象的数组,并展示在一个 table view 上。
let decoder = JSONDecoder() self.colors = try! decoder.decode([NamedColor].self, from: asset.data)
混合一下
Data set 通常无法从 Asset Catalog 的 App 瘦身特性中获益(例如,大部分的 JSON 文件都不太关心设备所支持的 Metal 版本)。
但是对于我们的调色板 App,我们可能为支持广色域显示的设备提供不同的颜色列表。
为了做到这一点,在 Asset Catalog 编辑器的侧边栏选中刚才的 asset,然后点击 Attributes Inspector 下名为 Gamut 的下拉控件。
为每个色域提供定制的数据文件后, contents.json
元数据文件应该看起来像这样:
{ "info": { "version": 1, "author": "xcode" }, "data": [ { "idiom": "universal", "filename": "colors-srgb.json", "universal-type-identifier": "public.json", "display-gamut": "sRGB" }, { "idiom": "universal", "filename": "colors-p3.json", "universal-type-identifier": "public.json", "display-gamut": "display-P3" } ] }
保鲜一下
使用 Asset Catalog 存储和获取数据是非常简单的。真正困难 —— 并最终更重要 —— 的是保持数据的更新。
使用 curl
、 rsync
、 sftp
、Dropbox、BitTorrent 或 Filecoin 刷新数据。从一个 shell 脚本开始(如果你喜欢,可以在 Xcode Build Phase 中调用它)。将它添加到你的 Makefile
、 Rakefile
、 Fastfile
,或者你的编译系统所要求的任何地方。将这个任务分配给 Jenkins、Travis 或者某个烦人的实习生。使用定制的 Slack integration 或者 Siri Shortcuts 触发它,这样你就可以用随意的一句 “Hey Siri,在数据变得太旧之前更新一下” ,让你的同事大吃一惊。
注意,当你决定同步你的数据时,一定要确保它是自动化的,而且是你发布过程的一部分。
下面是一个 shell 脚本示例,你可以运行它来使用 curl
下载最新的数据文件:
#!/bin/sh CURL='/usr/bin/curl' URL='https://example.com/path/to/data.json' OUTPUT='./Assets.xcassets/Colors.dataset/data.json' $CURL -fsSL -o $OUTPUT $URL
封装一下
虽然 Assets Catalog 会对 image asset 执行的无损压缩,但没有任何文档、Xcode 帮助或 WWDC 会议指出 data asset 上也存在这种优化(至少目前没有)。
当 data asset 的文件大小大于,比如说几百 KB 时,你就要考虑使用压缩了。JSON、CSV 和 XML 之类的文本文件尤其如此,它们通常可以被压缩到原始大小的 60% - 80%。
我们可以将 curl
的输出发送给 gzip
,然后再写到我们的文件,从而为我们之前的 shell 脚本添加压缩功能。
#!/bin/sh CURL='/usr/bin/curl' GZIP='/usr/bin/gzip' URL='https://example.com/path/to/data.json' OUTPUT='./Assets.xcassets/Colors.dataset/data.json.gz' $CURL -fsSL $URL | $GZIP -c > $OUTPUT
如果你使用了压缩,请确保 "universal-type-identifier"
字段体现了这一点:
{ "info": { "version": 1, "author": "xcode" }, "data": [ { "idiom": "universal", "filename": "colors.json.gz", "universal-type-identifier": "org.gnu.gnu-zip-archive" } ] }
在客户端上,你使用 asset catalog 之前需要先解压数据。如果有 Gzip
模块,你可能会做以下事情:
do { let data = try Gzip.decompress(data: asset.data) } catch { fatalError(error.localizedDescription) }
或者,如果你会在 App 中反复地这么做,那么可以在 NSDataAsset
的扩展中创建一个便利方法:
extension NSDataAsset { func decompressedData() throws -> Data { return try Gzip.decompress(data: self.data) } }
你还可以考虑使用 Git Large File Storage (LFS) 实现大型 data asset 文件的版本控制。
尽管你倾向于认为你的所有用户都享受着快速的、无处不在的 WiFi 和 LTE 网络,但这并不适用于所有人,也不适用于所有时段。
花点时间看看你的 App 在启动时发出的网络请求,然后考虑哪些可能从预加载中受益。给人留下好的第一印象可能意味着你的 App 是被长期地积极地使用着,而不是几秒钟之后就被删除。
本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问http://swift.gg。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。