调整你的网络代码
iOS中的网络栈包含几个用于与iOS设备的无线电硬件通信的接口。主要的编程接口是CFNetwork框架,它构建与Core Foundation框架的BSD套接字和不透明类型之上,用于与网络实体进行通信。你也可以使用Foundation框架中的NSStream类以及系统的Core OS层中的低级BSD套接字。
关于如何使用CFNetwork框架来进行网络连接的信息,参加CFNetwork Programming Guide 和 CFNetwork Framework Reference。关于使用NSStream类的信息,参见Foundation Framework Reference。
实现高效网络的技巧
实现用于通过网络接收或传输数据的代码,是设备上耗能最大的操作之一。把传输和接收数据的时间最小化可以帮助提高电池寿命。为此,你应该在编写网络相关的代码的时候考虑下面的技巧:
- 对于你控制的协议,在定义数据格式时尽可能的紧凑。
- 避免使用聊天(chatty)协议。
- 尽可能的一次传输较多的数据包。
蜂窝网络和Wi-Fi无线电被设计为非活动时关闭电源。这个动作,会消耗几秒钟。如果应用每隔几秒钟传输一个小数据,无线电或许会保持在这个状态且持续消耗电量,即使是不做任何操作的时候也是如此。所以与其经常性传输小数据,还不如一次传输一个较大的数据,两次传输之间的间隔大一些。
当与网络进行通信的时候,数据包可能随时丢失。所以,当编写网络代码的时候,你应妥善处理错误使代码强壮。实现对网络条件改变的响应是非常明智的,但是,如果这些处理没有始终如一的调用也不要意外。例如,Bonjour网络就不是当网络服务消失时马上会被回调。Bonjour系统服务会在它收到服务消失的通知的时候,里脊调用浏览回调。但是网络服务消失的时候不会有通知。如果设备提供网络服务意外失去网络连接,或者传输中通知丢失的时候,这种情况就可能发生。
使用Wi-Fi
如果应用使用Wi-Fi访问网络,你必须通过在应用的 Info.plist文件中包含UIRequiresPersistentWiFi 键,来通知系统。包含此键可以让系统指导它应该在检测到Wi-Fi热点的时候显示网络选择对话框。它也让系统知道,当应用运行的时候,不要尝试关闭Wi-Fi硬件。
为了防止Wi-Fi硬件消耗太多电量,iOS又一个内建的定时器,如果30分钟内没有应用通过UIRequiresPersistentWiFi键请求使用Wi-Fi,那么就会完全关闭Wi-Fi硬件,如果用户启动一个包含此键的应用,iOS会在应用生命周期内有效的禁用该定时器。但是,一旦应用退出或者进入挂起状态,系统就会重启这个定时器。
注意:注意,即使当UIRequiresPersistentWiFi的值是true,只要设备处于空闲(也就是,锁屏)时它也不起作用。该应用被认为无效,虽然它其他功能可能还有效,但是它不会有Wi-Fi连接。
更多 UIRequiresPersistentWiFi 键以及Info.plist文件的键的信息,参见The Information Property List File。
飞行模式警告
如果应用在设备处于飞行模式的时候启动,系统可能会显示一个警告,通知用户设备现处的状态。只有当符合以下所有条件的时候,系统才会显示这个警告:
- 应用的Info.plist文件包含UIRequiresPersistentWiFi键,并设该键的值为true。
- 应用在设备处于飞行模式的时候启动。
- 设备上的Wi-Fi在切换到飞行模式之后还没有重新手动启用。
改善你的文件管理
最小化你写入磁盘的数据量。文件操作相当慢,并且涉及写入闪存,它是有寿命限制的。下面是一些可以帮助你最小化文件操作的技巧:
- 仅写入文件更改的部分,并可以对更改进行合并。避免写入整个文件只是为了更改少数字节。
- 当定义文件格式的时候,经常性的将修改的内容组织在一起,以便最小化每次需要写入磁盘的数据量。
- 如果数据是由随机访问的结构化内容组层,把它存储在Core Data或者SQLite数据库,特别是当你操作的数据会不断成长的时候。
避免把缓存文件写入磁盘。此规则的唯一例外是,当应用退出以及需要写入状态信息的时候,这些内容会在应用下次启动的时候将应用恢复到之前的状态。
使用程序备份更有效率
备份可以通过iCloud或者当用户使用iTunes同步设备的时候发生。通过备份,文件将从设备传输到用户的电脑或者是iCloud账户。在应用沙盒中的文件位置决定了这些文件能否备份以及恢复。如果你的应用创建了很多频繁更改的大型文件,并将其放在备份的位置,备份的过程将非常缓慢。就像你写文件管理代码一样,你需要注意这个情况。
应用备份最佳实践
应用无需为备份或恢复做准备。带有激活的iCloud账户的设备,会在合适的时候把数据备份到iCloud。对于插入计算机的设备,iTunes会对应用的数据文件执行一个增量备份。但是iCloud和iTunes不会备份下列目录里的内容。
- <Application_Home>/AppName.app
- <Application_Data>/Library/Caches
- <Application_Data>/tmp
为了防止同步过程花费太长时间,选择应用的主目录放置文件。存储大型文件的应用的备份过程会非常慢。这些应用也消耗大量用户的可用存储空间,这可能会导致用户删除该应用,或者禁止应用备份到iCloud。考虑到这一点,你应该根据下面的准则来存储应用数据:
- 至关重要的数据应该存储在<Application_Data>/Documents目录。至关重要的数据是那些不能够通过应用创建的数据,例如用户文件,以及其他用户生成的内容。
- 支持文件包括应用下载或生成的文件,以及应用能在需要时创建的文件。存储应用的支持文件的位置依赖于当前iOS的版本。
- 在iOS5.1及更高版本,支持文件保存在<Application_Data>/Library/Application Support目录,并且使用setResourceValue:forKey:error:方法添加NSURLIsExcludedFromBackupKey属性到相应的NSURL对象。(如果你使用Core Foundation,使用CFURLSetResourcePropertyForKey函数将kCFURLIsExcludedFromBackupKey键添加到你的 CFURLRef对象。)申请这些属性,防止文件被备份到iTunes或iCloud。如果你有很多支持文件,你应该把它们存储在自定义的子目录中,并为适应目录而申请扩展属性。
- 在iOS5.0及更早版本,在<Application_Data>/Library/Caches 目录保存支持支持文件,来防止备份。如果目标是iOS5.0.1,参见How do I prevent files from being backed up to iCloud and iTunes?获取关于从备份中排除文件的信息。
- 缓存数据应该保存在<Application_Data>/Library/Caches目录。你应该放在Caches目录里的文件包括(但不限于)数据库缓存文件以及可下载内容,例如杂志、报纸、地图应用使用的文件。应用应该能够优雅的处理缓存数据被系统删除以便释放磁盘空间的情况。
- 临时数据应该被保存在<Application_Data>/tmp目录。临时数据包括任何你不需要长时间持有的数据。当你使用完的它们的时候要记得删除,以便它们不浪费用户设备的空间。
虽然iTunes备份应用束本身,但它不会在每次同步操作的时候都这样做。直接从设备购买的应用会在设备下次和iTunes同步的时候备份。除非应用束有改变(例如应用有更新),否则应用不会在同步操作期间进行备份。
关于如何使用应用中的目录的更多指导,参见File System Programming Guide。
在应用更新期间保存文件
当用户下载应用的更新的时候,iTunes在一个新的应用目录里安装更新。然后把用户的数据文件从旧安装位置移动到新的安装位置。然后再删除旧的安装内容。在以下目录中的文件会在更新期间会得到保护。
- <Application_Data>/Documents
- <Application_Data>/Library
尽管在其他用户目录中的文件也可以被移动,但你不应该在更新后依然依靠它们存在。
将工作移出主线程
确保限制可以在应用主线程上进行工作类型。主线程是应用处理触摸事件和其他用户输入的地方。想要确保应用总是对用户有响应,你就永远不要在主线程上执行长时运行或无时限任务,例如访问网络的任务。相反,你应该把这些任务移动到后台线程。首选的方式是使用Grand Central Dispatch(GCD)或者NSOperation对象来异步执行任务。
把这些任务移动到后台,可以让你的主线程可以继续处理用户输入,这对应用的启动或退出尤其重要。在这些时候,应用被希望能够及时响应事件。如果应用的主线程在且哦哪个的时候被阻止,系统会在启动完成之前杀死应用。若果主线程在退出的时候被阻止,系统会在应用又机会写出关键用户数据之前杀死应用。
更多关于使用GCD、操作对象、以及线程的信息,参见Concurrency Programming Guide。