iOSiOS开发资源iOS开发经验与总结

App Programming Guide for iOS读书笔

2016-04-26  本文已影响2138人  没阳光的午后

这是阅读该指南的一些笔记,说说是笔记,其实就是把一些自己决定重要的知识给翻译了一遍,因为英文读着读着就把前面的给忘了。。。所以就打算记录一点。该文章会慢慢更新,这段时间打算将几篇重要的指南都重新看一遍,每天都会更新这些笔记,英语不大好,可能有翻译错误的地方,请大家指出,谢谢!

APP状态

在任何时间上,你的APP只有一个状态,看表Table 2-3.系统切换APP状态来响应系统事件.举例,当用户按下Home键,一个电话打来,或者其他中断的行为,当前运行的APP改变状态来响应.Figure 2-3 显示一个APP改变状态的路径.

状态 描述
没有运行 该APP没有运行或者正在运行但被系统终止
不活跃的 该APP在前台运行,但没有接受到事件,APP一般都处在这个状态
活跃 该APP在前台运行并且接受事件,这是前台运行APP正常状态
后台 该APP在后台且在执行代码,大部分APP在该状态会停留一段事件
暂停 该APP在后台且没有执行代码,系统会自动将APP设置到这个状态并不会通知APP.暂停后,APP保留在内存内但不会执行代码.当内存低时,系统会杀死APP来使前台有更多内存

大多数状态的改变都伴随着系统方法的调用。你可以在这些方法内响应状态。

本节讲了应用各种运行的状态和appdelgate里一些方法具体是什么时候被调用的

APP终止

APP应该随时准备被终止而不应该等待保存用户数据或者执行关键任务,系统发起的终止是APP生命周期里的一个正常环节。
如果APP正在后台运行且没有暂停,系统会在应用终止前调用applicationWillTerminate,如果系统重启,不会调用这个方法

线程和并发

系统创建主要的线程,你也可以创建额外的线程。对于iOS APP,你应该首选GCD,操作队列和其他的异步接口而不是自己创建和管理线程,使用GCD可以让你更好的专注于工作,让系统去处理线程相关的事情。

在思考线程和并发时,你应该注意以下几点

更多的GCD或者操作队列信息请看 Concurrency Programming Guide

本节讲了耗时操作能放在子线程就丢到子线程,除了创建视图,刷新视图等等。。

Strategies for Handling App State Transitions

可以在UIApplicationDelegate协议方法里面知道状态改变。

What to Do at Launch Time

当APP启动时(无论是前台还是后台),在application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:方法内做以下几点:

在启动时候要尽快完成,超过5秒系统会自动杀死该进程。

The Launch Cycle

应用进入运行状态流程图

应用在后台会处理事件,并会在某个时间点暂停。它仍会加载界面文件但不会显示

可以通过applicationState属性区别当前应用状态,在前台时为UIApplicationStateInactive,后台时为UIApplicationStateBackground

Launching in Landscape Mode

应用必须设置朝向,如果支持横向和纵向,那么默认是纵向。如果只支持横向,需要做到以下几点:

What to Do When Your App Is Interrupted Temporarily

当应用暂时中断时,系统仍在前台但是不能接受触摸事件,但可以接受类似陀螺仪事件,你需要在applicationWillResignActive:方法内做以下操作:

在应用进入活跃状态时,在applicationWillResignActive方法内你应该重启定时器,恢复队列。游戏不应该恢复,这应该让用户手动开始。

Responding to Temporary Interruptions

假如有电话打来,应用会进入inactive状态,直到用户结束通话,应用回到活跃状态或者后台。

用户拉下通知横幅会造成应用进入inactive状态。
用户按下锁屏键,系统禁用触摸事件并且使应用进入后台,这时候数据文件会被加密保护起来。

What to Do When Your App Enters the Foreground

当应用进入前台状态时,applicationWillEnterForeground:方法会撤销所有applicationDidEnterBackground:方法里的事情,并在applicationDidBecomeActive:方法里做激活任务。

UIApplicationWillEnterForegroundNotification这个枚举也可以用来监听应用进入前台状态。

Be Prepared to Process Queued Notifications

Event Notifications
配件断开或链接 EAAccessoryDidConnectNotification
屏幕旋转 UIDeviceOrientationDidChangeNotification
完整一天过去 UIApplicationSignificantTimeChangeNotification
偏好设置改变 NSUserDefaultsDidChangeNotification
语言改变或者区域改变 NSCurrentLocaleDidChangeNotification

应用在后台时仍然能调用setNeedsDisplay或者setNeedsDisplayInRect:,但是因为视图是不显示的,所以会在下次应用进入前台时更新视图。

What to Do When Your App Enters the Background

从前台进入后台,在applicationDidEnterBackground:方法里做以下几点:

应用在applicationDidEnterBackground:方法里大概有5秒的时间来完成任务。实际上,这个方法应该尽可能快的返回。如果方法没有在时间耗尽前返回,系统会杀掉应用并释放内存。如果你需要长时间进行任务,你应该在beginBackgroundTaskWithExpirationHandler:方法里进行,并且在secondary线程上。不管你在applicationDidEnterBackground:方法内进行任何操作都必须在5秒内返回。

Note:UIApplicationDidEnterBackgroundNotification这个枚举可以知道系统进入后台

The Background Transition Cycle

当用户按下Home键,关机键或者打开其他应用,前台应用会变到inactive状态然后到background状态。这些转变结果会调用到applicationWillResignActive:applicationDidEnterBackground:方法。在applicationDidEnterBackground:方法返回后,大多数应用会在不久后变到suspended状态。如果应用需要特殊的后台任务(像播放音乐)或者执行额外的长时间任务,background状态会延长。

Prepare for the App Snapshot

applicationDidEnterBackground:方法返回不久后,系统会生成一张应用快照用于显示。同样,当应用被唤醒来处理一些后台任务,系统也许需要生成一张新的快照来反映改变。

如果你想对显示的快照做更改,你需要调用snapshotViewAfterScreenUpdates:来更新视图,这个方法能马上更新视图,调用setNeedsDisplay方法是没用的,这个上面文档讲过了。


Strategies for Implementing Specific App Features

不同的应用有不同的需要,但是有些行为应该是相同的。下面的章节会介绍这些特定的功能如何实现。

Privacy Strategies

保护用户隐私对于应用来说是很重要的。系统已经提供了保护隐私的方法。

Protecting Data Using On-Disk Encryption

设备锁屏以后,是不能访问被保护的文件的,就算文件是应用创建的也不可以。想访问保护文件必须在设备解锁之后。

数据保护在大部分设备上是可用的,只需要遵循以下几点:

使用NSDataNSFileManager类可以通过添加属性来设置保护等级。当写入新文件时,你可以使用NSDatawriteToFile:options:error:方法。对于已存在的文件,你可以使用NSFileManagersetAttributes:ofItemAtPath:error:方法,使用这些方法,你可以设置以下几个保护等级:

如果你保护了文件,那么应用会随时不能访问文件。当设备锁屏时,你可以通过几点知道是否可以访问文件:

反正就是推荐文件保护。

Identifying Unique Users of Your App

你应该区别每一个用户,并且这一行为应该是透明的。

在以下几种情况下,也许你需要这样做

如果你需要在不同设备上辨认是否是一个用户,你需要提供自己的一套识别系统。

Supporting Multiple Versions of iOS

一个在多个版本运行的应用应该检查系统版本,防止在旧系统上使用了新系统的API。

有几个检查方法你可以选择:

if ([UIPrintInteractionController class]) {
   // Create an instance of the class and use it.
}
else {
   // The print interaction controller is not available so use an alternative technique.
}
if (UIGraphicsBeginPDFPage != NULL) {
    UIGraphicsBeginPDFPage();
}

想知道这方面更多的知识,可以看 SDK Compatibility Guide.

Preserving Your App’s Visual Appearance Across Launches

Enabling State Preservation and Restoration in Your App

状态保存和恢复不是自动的,系统必须选择使用。如果要使用这些功能,需要实现以下方法
application:shouldSaveApplicationState:application:shouldRestoreApplicationState:

一般来说,返回YES是表明功能可用。但是有些时候需要返回NO,比如应用更新了,你不应该恢复旧的页面。

The Preservation and Restoration Process

在保存和恢复过程中,应用也有少量的任务:

Figure 5-1 显示了简单的视图控制器的层次结构。如果没有状态恢复,只有main storyboard文件里的控制器在随后的启动中恢复。当你的应用支持状态恢复,你可以保存所有的控制器

UIKit保存对象需要一个保存identifier,假如控制器没有这个identifier,他和他的子视图都不会被保存。Figure 5-2 展示了部分拥有identifier的控制器

这些功能对于应用来说也许是毫无意思的,因为UIKit本身就能简单的保存和恢复。

对于你保存的所有控制器 ,你也需要决定如果去恢复它们。UIKit 提供了两种方式去创建对象。你可以去重新创建它们或者通过 view controller 去恢复它们。restoration class实现UIViewControllerRestoration协议,并且在恢复的时候去负责寻找或者创建指定的对象。这里有几个建议:

在保存过程中,UIKit 保存对象并且写入到磁盘。每个控制器也有一次机会来保存数据。

Flow of the Preservation Process

Figure 5-3 展示了直到保存状态前的高级事件和应用是如何被影响的。在保存之前,UIKit 会调用application:shouldSaveApplicationState:方法,如果返回YES的话会开始保存视图。

下次应用启动的时候会自动寻找保存状态的文件,如果有的话就恢复。因为这些文件只适用于上次和当前的周期,在启动后会删除上次的保存状态文件。在恢复过程中有错误也会删除保存状态文件。举例,在一次恢复过程中应用崩溃了,那么系统会自动删除文件防止下次恢复再崩溃。

What Happens When You Exclude Groups of View Controllers?

Figure 5-5 展示了当导航控制器没有保存identifier,他的子控制器和视图都不会被保存

即使你不保存控制器,也不意味着所有控制器从视图层次中消失了。举个例子,如果有控制器是从 storyboard 文件中加载的,他会一直显示。

Checklist for Implementing State Preservation and Restoration

你如果想通过代码来实现保存和恢复状态,你应该看看以下几点:

Preserving the State of Your View Controllers

保存单独的控制器状态,你需要做到以下几点:

Marking Your View Controllers for Preservation

UIKit 只会恢复拥有有效 restorationIdentifier 的对象。

恢复路径是从上往下。

Restoring Your View Controllers at Launch Time

在恢复过程中,UIKit 会通过几种办法去恢复:

以下代码展示了如果在恢复过程中创建控制器。

+ (UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
                      coder:(NSCoder *)coder {
   MyViewController* vc;
   UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
   if (sb) {
      vc = (PushViewController*)[sb instantiateViewControllerWithIdentifier:@"MyViewController"];
      vc.restorationIdentifier = [identifierComponents lastObject];
      vc.restorationClass = [MyViewController class];
   }
    return vc;
}

Inter-App Communication

应用之间可以通过 URL 来进行通信。

Supporting AirDrop

AirDrop 可以发送图片,文件,URLs,和其他类型的数据给附近的设备。AirDrop 通过 peer-to-peer 网络来寻找附近的设备。

Sending Files and Data to Another App

如果想通过 AirDrop 发送文件和数据,使用UIActivityViewController对象。当你创建了这个控制器,
你可以指定你想显示什么。你也可以显示自定义对象,只要遵守UIActivityItemSource协议。

你可以通过excludedActivityTypes属性来指定不显示的类型。当显示一个 activity view controller 在iPad上时,你必须使用popover

在iPhone上显示 activity view controller

- (void)displayActivityControllerWithDataObject:(id)obj {

   UIActivityViewController* vc = [[UIActivityViewController alloc]

                                initWithActivityItems:@[obj] applicationActivities:nil];

    [self presentViewController:vc animated:YES completion:nil];
}

Receiving Files and Data Sent to Your App

使用 AirDrop 接受文件你需要注意以下几点:

传输到 Documents/Inbox 中的文件你只能读取或者删除,但不能修改

Using URL Schemes to Communicate with Apps

Apple 内置了很多 URL schemes。如果你的 URL 定义了一个和 Apple 相同的东西,那么在你应用启动时会打开 Apple 的应用。

Sending a URL to Another App

当你实现自定义的 URL scheme 来发送数据给别的应用,调用openURL:方法。

以下代码展示了一个应用如何打开另一个应用

NSURL *myURL = [NSURL URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"];

[[UIApplication sharedApplication] openURL:myURL];

如果应用自定义了一个 URL scheme ,请看Implementing Custom URL Schemes

PS: iOS9新增了一个白名单,苹果规定开发者只能设置50个 URL scheme 来打开别的应用,在openURL:之前还需要做个判断canOpenURL:,返回到前一个应用不用这样做。

Implementing Custom URL Schemes

如果你的应用可以接收特定的 URLs,你应该在系统里注册相应的 URL schemes。

Registering Custom URL Schemes

在应用里注册 URL 类型,你应该在 Info.plist 文件中加入CFBundleURLTypes key。这个 key 包含一个字典数组,每一个都定义了一个 URL schemes。

Key Value
CFBundleURLName 字符串包含了一个 URL scheme。为了确保唯一性,推荐指定一个反向域名格式的标识,举个例子, com.acme.myscheme。
CFBundleURLSchemes 字符串数组包含了 URL scheme 名字,举个例子,http, mailto, tel, 和 sms。

Note: 如果多个第三方应用使用了相同的 URL scheme,目前还没有好的办法来解决。

Handling URL Requests

每个应用都有自己自定义的 URL scheme 并且也该知道如何去处理它们。你应该在 delegate 中实现以下方法:

Figure 6-1 展示了在一个要求打开网址的应用上显示修改好的启动顺序

Figure 6-2 展示了切换到前台状态打开 URL

Displaying a Custom Launch Image When a URL is Opened

应用支持自定义的 URL schemes 可以提供自定义的启动图片。当系统启动你的应用通过 URL 时并没有有效的快照,他会显示你指定的启动图片。指定一个启动图片,提供一张使用以下名字格式的 PNG 图片:

basename代表了基本的图片名字,假如名字是 Default,url_scheme 是你的 URL scheme 的一部分名字,假如 URL scheme 是 myapp,那么你的启动图片名字就是 Default-myapp@2x.png。


Performance Tips

本章讲述整体性能的几点。

Reduce Your App’s Power Consumption

功耗始终是移动设备上的一个大问题。你可以通过优化以下几个功能来提高电池寿命:

你应该经常使用 Instruments 来优化算法。但是即使最优算法也会对电池寿命有意向。你应该在写代码的时候注意以下几点:

访问网络数据是很耗电的,通过以下几点来使访问数据次数最小化:

Instruments 应用包含了几个收集电池信息的 Instruments。还可以收集指定硬件耗电量。你也可以使用诊断记录来收集信息。PS:这个在手机设置里可以看。

Use Memory Efficiently

系统的可用内存会影响应用的性能。

Observe Low-Memory Warnings

系统发出内存警告时应该移除不需要的对象。回应这个警告是很重要的否则系统可能会终止应用。系统通过以下几个 API 来发送内存警告:

收到内存警告你应该释放掉不需要的内存。例如清理缓存,释放图片。如果你有一个不用的大数据,应该把它写进磁盘。

你可以通过UIApplicationDidReceiveMemoryWarningNotification通知来直接删除不需要的资源。

Reduce Your App’s Memory Footprint

Table 7-1 减少应用内存占用空间

Tip Actions to take
清楚内存泄露 在iOS中内存是很关键的资源,你的应用不应该有内存泄露。使用 Instruments 查看是否有内存泄露。
资源文件尽可能的小 文件写入到磁盘之前会在内存中存在。尽可能的压缩图片文件(PNG 图片是 iOS 首选的图片格式)。
懒加载资源 在需要使用要资源时再加载。

后面这些很多都在之前的文档有讲到,感兴趣的朋友可以自己去翻阅一下。

上一篇 下一篇

猜你喜欢

热点阅读