• NSURLSession是iOS7中新的网络接口,它与NSURLConnection是并列的,程序在前台时,NSURLSession与NSURLConnection可以互为替代工作,注意,如果用户强制将小横须关闭,NSURLSession会断掉。

  • NSURLSession的功能:

  1. 通过URL将数据下载到内存
  2. 通过URL将数据下载到文件系统
  3. 将数据上传到指定URL
  4. 在后台完成上述功能
  • 工作流程
    1.创建一个NSURLSessionConfiguration,用于第二部创建NSSession时设置工作模式和网络设置,工作模式分为:
    • 一般模式(default):工作模式类似于NSURLConnection,可以使用缓存的Cache,Cookie,鉴权
    • 及时模式(ephemeral):不使用缓存的Cache,Cookie,鉴权
    • 后台模式(background):在后台完成下载,创建Configuration对象的时候需要给一个NSString的ID用于跟踪完成工作的Session是哪一个
      网络设置:参靠NSURLConnection中的设置项。
  1. 创建一个NSURLSession。系统提供了两个创建方法

    • sessionWithConfiguration:
    • sessionWithConfiguration:delegate:delegateQueue:

    • 第一个粒度较低就是根据刚才创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息。

    • 第二个粒度比较高,可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。

  2. 创建一个NSURLRequest调用刚才的NSURLSession对象提供的Task函数,创建NSURLSessionTask
    • 根据智能不同Task有三个子类:
      • NSURLSessionUploadTask:上传用的Task,传完以后不会再下载返回结果;
      • NSURLSessionDownloadTask:下载用的Task;
      • NSURLSessionDataTask:可以上传内容,上传完成后再进行下载;
    • 得到的Task,调用resume开始工作
  3. 如果是细粒度的Session调用,Session与Delegate会在指定的OperationQueue中进行交互,以下载例子,交互的顺序图如下(假设不需要鉴权,即非HTTPS请求):
  4. 当不再需要连接调用Session的invaildateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBeComeInvaliWithErro:这个事件。Delegge收到这个事件之后会被解引用。
  5. 如果是一个BackgroundSession,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互,当程序切到后台后,在BackgroundSession中的Task还会继续下载

1)当加入了多个Task,程序没有切换到后台
这种情况Task会按照NSURLSessionConfiguration设置正常下载,不和和ApplicationDelegate有交互。

2)当加入了多个Task,程序切换到后台,所有Task都完成下载。
在切换到后台之后,Session的Delegate的application:handleEventForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)
之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession

  • 注意:在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@implementation APLAppDelegate 



- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier

completionHandler:(void (^)())completionHandler

{

BLog();

/*

Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed).

*/

self.backgroundSessionCompletionHandler = completionHandler;

}

//……

@end



//Session的Delegate

@implementation APLViewController



- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

{

APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];

if (appDelegate.backgroundSessionCompletionHandler) {

void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;

appDelegate.backgroundSessionCompletionHandler = nil;

completionHandler();

}



NSLog(@"All tasks are finished");

}

@end

3)当加入了多个Task,程序切换到后台,下载完成了几个Task,然后用户又切换到前台。(程序没有退出)

  • 切换到后台之后,Session的Delegate仍然收不到消息,在下载完成几个Task之后再切换到前台,系统会先汇报已经下载完成的Task的情况,然后继续下载没有下载完成的Task。

4)当加入了多个Task,程序切到后台,几个Task已经完成,但还有Task还没有下载完的时候关掉退出程序然后再进入程序的时候。(程序退出了)

  • 块语法与其他变量类似,不同的是,代码块存储的数据是一个函数体。使用代码块时,可以想调用其他标准函数一样,传入参数,并得到返回值
  • 脱字符(^)是块的语法标记,按照参数语法定义返回值以及快主题

    按照调用函数待方式调用块对象变量就可以了:
    int result = myBlock(4)// result = 28
  • 例子
  1. 参数是NSString*的代码块

    1
    2
    3
    4
    5
    6
    void (^printBlock)(NSString *x)
    printBlock = ^(NSString* str)
    {
    NSLog(@"print:%@",str);
    }
    printBlock(@"hello world");
  2. 代码用在字符串数组排序

    1
    2
    3
    4
    5
    6
    7
    NSArray *stringArray = [NSArray arrayWithObjects:@"abc 1",@"abc2",@"abc 3",@"abc 4",nil];
    NSCompartor sortBlock = ^(id string2,id string2)
    {
    return [string1 compare:string2];
    }
    NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];
    NSLog(@"sortArray:%@",sortArray);
  3. 代码快的递归调用

    1
    2
    3
    4
    5
    6
    7
    8
    static void(^ const blocks)(int) = ^(int)
    {
    if(i > 0){
    NSLog(@"num:%d",i);
    blocks(i - 1);
    }
    };
    blocks(3);
  4. 在代码块中使用局部变量和全局变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int global = 1000;
    int main(int argc,const char * argv[])
    {
    @autoreleasepool{
    void(^block)(void) = ^(void)
    {
    global++;
    NSLog(@"global:%d",global);
    }
    block();
    NSLog(@"global:%d",global);
    }
    return 0;
    }

Objective-C集合

  • 大致可分为:NSArray、NSSet、NSDictionary三种体系,NSAarray代表有序、可重复的集合,NSSet代表无序、不可重复的集合,NSDictionary代表具有映射关系的集合。

    数组(NSArray和NSMutableArray)

  • NSArray代表元素有序、可重复的一个集合,集合中每一个元素都有对应的顺序索引。
    -常用方法
    • array:创建一个不包含任何元素的空NSArray
    • arrayWithContentsOfFile:/initWithContentsOfFile:读取文件内容来创建NSArray
    • arrayWithObject:/initWithObject:创建只包含指定元素的NSArray
    • arrayWithObjects:/initWithObjects:创建包含指定N个元素的NSArray
    • objectAtIndex:根据索引返回元素
    • lastObject:最后一个元素
    • objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRnnge:NSMakeRange(2,3)] 从索引中2~5的元素组成新集合
    • indexOfObject:查找元素的位置
    • indexOfObject: inRange:查找指定范围内元素的位置
    • arrayByAddingObject: 追加元素
    • arrayByAddingObjectsFormArray:追加数组集合
    • writeToFile:写入文件

Android安全概述

  • 安全主要解决4类需求:
    • 保密(Security/Confidentiality
    • 鉴别/认证(Authentication)
    • 完整性(Integrity)
    • 不可否认性(non-repudiation)
  • 好的密码术应该是算法公开密钥保密的。

对称加密概述

  • 典型的加密模型
    • 秘钥:分为加密秘钥和解密秘钥。
    • 明文:文友进行机密,能够直接表带原文含义的信息。
    • 密文:经过加密处理处理之后,隐藏原文含义的信息。
    • 加密:将明文转换成密文的实施过程。
    • 解密:将密文转换成明文的实施过程。
  • 对称的含义(Symmetric)
    • 加密和解密用同一套Key
  • 置换加密、转置加密和乘积加密
    • 置换加密,又称换位密码,是一个简单的换位,每个置换都可以用一个置换矩阵Ek来表示。每个置换都有一个与之对应的逆置换Dk。
  • DES
  • AES
  • 优点和缺点
    • 高效
    • 秘钥交换的问题
    • 不如RSA的加密安全程度高,但当选择256bit的AES仍然能胜任大多数安全领域。

非对称加密

  • 非对称加密的模型
  • 公钥和私钥
  • RSA
    • 建立在分解大树的困难度上,公钥/私钥长度至少1024bit
  • 优点和缺点
    • 安全性足够高
    • 没有密钥交换的问题
    • 效率低,对于大数据加密很慢

      常见场景

  • 保密会话

CoreAnimation动画

  • CoreAnimation动画使用CALayer来创建用户界面,每个UIView上可以放置几百个CALayer,各个大小不同的CALayer叠加、组合在一起,各CALayer可以自由地控制它们的位置、大小和形状,这样就可以创建复杂的用户界面。
  • CoreAnimation床架动画不仅简单而且具有更好的性能,原因如下:
    • CoreAnimation动画在单独的线程中完成,不会阻塞主线程。
    • CoreAnimation动画只重绘界面上的局部变化(局部刷新)。

  1. Objective-C里面没有public和private的概念,你可以认为全是public。
  2. NS代表NextStep,CF代表CoreFoudation,CG代表CoreGraphics,CA代表CoreAnimation,UI代表UserInterface
  3. id代表万能指针
  4. BOOL本质上是char,NO代表false,YES代表true
  5. nil 就是NULL

字符串(NSString与NSMutableString)

  • NSString代表字符串序列不可变的字符串,NSMutableString代表序列可变的字符串
  • NSString常用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    NSString *str = @"This is a String!";//以字符串常量创建字符串
    NSString *str = [[NSString alloc] init];
    str = @"This is a String!";//创建空字符串,赋值
    NSString *str = [[NSString alloc] initWithString:@"This is a String!"//初始化字符串
    char *Cstring = "This is a String!"
    NSString *str = [[NSString alloc] initWithCString:Cstring];//以标准c字符串初始化创建字符串
    NSString *str = [[NSString alloc] stringWithFormat:@"%s is a String","This"];//格式化创建字符串
    NSString *path = [[NSBundle mainBundle] pathForResouce:@"text" ofType:@"txt"];
    NSString *str = [[NSString alloc] initWithContentsOfFile:path];//从文件创建字符串
    [str writeToFile:path atomically:YES];//写入文件
    BOOL result = [str1 isEqualToString:str2];//判断相等与否
    str = [str stringByAppendingString:@"iOS!"];//追加字符串
    char* cstr = [str UTF8String];//获取字符串对应的C风格字符串
    [str length];//获取字符串长度
    [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];//str按UTF-8字符集解码后字节数
    [str substringToIndex:10];//获取str的前10个字符组成的字符串
    [str substringFromIndex:5];/获取从第5个字符串开始,与后面字符组成的字符串
    [str substringWithRange:NSMakeRange(5,15)];//获取str从第5个字符开始,到第15个字符组成的字符串
    [str rangeOfString:@"ios"];//返回ios在字符串中出现的位置
    [str uppercassString];//str所有字符转为大写
  • NSMutableString可改变序列

  • NSMutableString常用方法
    1
    2
    3
    4
    5
    [str appendString:@",iOS"];//追加固定字符串
    [str appendFormat:@"%s is ios",@",iOS"];//追加字符串
    [str insertString:@"insert" atIndex:6];//指定位置插入字符串
    [str deleteCharactersInRange:NSMakeRange(6,12)];//删除6到12位置的所有字符串
    [str replaceCharactersInRange:NSMakeRange(6,9) withString:@"Objective-C"];//替换6到9位置的字符串

日期与时间(NSDate)

  • 常用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    NSDate* date1 = [NSDate date];//获取代表当前日期、时间的NSDate
    NSDate* date2 = [[NSDate alloc] initWithTimeIntervalSinceNow:3600*24];//获取从当前时间开始3天之后的日期
    NSDate* date3 = [NSDate dateWithTimeIntervalSince1970:3600*24*366*20];//从1970年1月1日开始,20年之后的日期
    NSLo
    cale* cn = [NSLocale currentLocale];//获取本地位置
    [dete1 descriptionWithLocal:cn];//过去NSDate在当前位置对应的字符串
    [date1 earlieDate:date2];//获取两个日期之间较早的日期
    [date laterDate:date2];//获取两个日期之间较晚的日期
    switch([date1 compare date2])
    {
    case NSOrderedAscending:
    break; //date1在之前
    case NSOrderedSame:
    break; //date1与date2日期相同
    case NSOrderedDescending:
    break; //date1在之后
    }
    [date1 timeIntervalSinceDate:date2];//时间差
    [date1 timeIntervalSinceNow];//与现在时间差
    • NSLocale待遇一个语言、国际环境

日期格式器(NSDateFormatter)

  • NSDateFoematter代表一个日期格式器,用来完成NSDate与NSString之间的转换
  1. 创建一个NSDateFormatter对象
  2. 调用NSDateFormatter的setStyle:setTimeStyle:方法设置格式化日期、时间的风格,日期、时间风格支持如下的枚举值:
    • NSDateFormatterNoStyle:不显示日期、时间的风格
    • NSDateFormatterShortStyle:显示“短”的日期、时间风格
    • NSDateFormatterMediumStyle:显示“中等”的日期、时间风格
    • NSDateFormatterLongStyle:显示“长”的日期、时间风格
    • NSDateFormatterFullStyle:显示“完整”的日期、时间风格
  3. NSDate转换成NSString可以调用NSDateFormatter的stringFromDate:方法执行格式化即可
  4. NSString转换成NSDate可以调用NSDateFormatter的dateFromString:方法执行格式化即可
    1
    2
    3
    4
    // 自定义格式式模板
    NSDateFormatter* df = [[NSDateFormatter alloc]init];
    [df setDateFormatter:@"公元yyyy年MM月DD日HH时mm分"];
    NSLog(@"%@",[df stringFromDate:date]);

日历(NSCalendar)与日期组件(NSDateComponents)

  • NSCalender对象用于处理NSDate对象所包含的各个字段的数据
  • NSCalendar常用方法
    • (NSDateComponents*)components:fromDate:从NSDate提取年、月、日、时、分、秒各时间字段的信息。
    • dateFromComponents:(NSDateComponents*)comps:使用comps对象包含的年、月、日、时、分、秒各时间字段的信息来创建NSDate.

定时器(NSTimer)

  1. 调用NSTimer的scheduledTimerWithTimeInterval:invocation:repeats:或scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:类方法来创建NSTimer对象。
    • timerInterval:指定每个多少秒执行一次任务。
    • invocation或target与selector:指定重复执行的任务。如果指定target和selector参数,则指定用某个对象的特定方法作为重复执行的任务;如果指定invacation参数,该参数需要传入一个NSInvocation对象,其中NSInvocation对象也是封装target和selector的,其中也是指定用某个对象的特定方法作为重复执行的任务。
    • userInfo:该参数用于传入额外的附加信息。
    • repeats:该参数需要指定BOOL值,该参数控制是否需要重复执行任务。
  2. 为第一步的任务编写方法。
  3. 销毁定时器,调用定时器的invalidate方法即可。

对象复制

  • NSObject类提供了copy和mutableCopy方法,通过这两个方法即可复制已有对象的副本。
  • copy方法总是返回不可修改的副本,及时改对象本身是可修改的。
  • mutableCopy方法用于复制对象的可变副本,即便对象本事是不可修改的,如NSString,返回的是NSMutableString对象。

NSCopying与NSMutableCopy协议

  • 为了保证自定义类能够使用copy、mutableCopy方法,需要做如下的事
    • 让该类实现NSCopying(NSMutableCopying)协议
    • 让该类实现copyWithZone:(mutableCopyWithZone:)方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      -(id)copyWithZone:(NSZone*)zone
      {
      ZTApple apple= [[[self class] allocWithZone:zone]init];
      ZTApple.color = self.color;
      ZTApple.weight = self.weight;
      return apple;
      }
      // 如果父类已经实现了NSCopying协议,那么代码就可简化
      -(id)copyWithZone:(NSZone*)zone
      {
      id obj = [super copy];
      //...
      return obj;
      }

浅复制(shallow copy)与深复制(deep copy)

  • 当对象的实例变量是指针变量时,程序只是复制该指针的地址,而不是真正复制指针指向的对象,这种方式被称为“浅复制”,对浅复制而言,在内存中复制了两个对象,这两个对象的指针变量将会指向同一个对象,也就是两个对象存在公用的部分。
  • 深复制不仅会复制对象本身,而且会“递归”复制每个指针类型的实例变量,直到两个对象没有任何公用的部分。

    1
    2
    3
    4
    5
    6
    7
    -(id)copyWithZone:(NSZone*)zone
    {
    ZTApple apple= [[[self class] allocWithZone:zone]init];
    ZTApple.color = [self.color mutableCopy];
    ZTApple.weight = self.weight;
    return apple;
    }
  • 一般来说,Foundation框架中的类大部分只实现了浅复制。

    setter方法的copy选项

  • setter的copy只实现copy方法,得到的回事一个不可变的副本。

  • NSBundle用来访问应用自包含的资源文件。
  • 获取NSBundle对象,一般会调用该类的mainBundle方法。
    • URLForResource:withExtension:subdirectory:根据资源名扩展名从指定子目录获取对用资源的URL
    • URLForResource:withExtension:根据资源名扩展名获取该资源对应的URL
    • pathForResouce:ofType:根据资源名类型名获取该资源对应的路径
    • URLsForResoucesWithExtension:subdirectory:获取指定子目录下匹配特定扩展名的所有资源对应的URL组成的数组
    • pathForResouces:ofType:inDirectory:从指定的子目录下,根据资源名,类型名获取该资源对应的路径
    • pathForResoucesOfType:inDirectory:获取指定子目录下,匹配特定类型名的所有资源对应的路径组成的数组
    • resoucePath:直接根据完整的资源路径来获取对应的资源
      1
      2
      NSString* filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"];
      NSString* content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

  • 归档就是用户某种格式把一个或者多个对象保存到指定的文件中,方便以后从文件中恢复它们。

使用NSKeyedArchiver归档

  • NSKeyedArchiver负责将对象归档到指定文件中
  • NSKeyedUnarchiver则负责从文件中恢复对象

    • 直接调用archivedDataWithRootObject:dataarchiveRootObject:toFile:file类方法将指定对象作为root进行归档;恢复时,则调用NSKeyedUnarchiver的unarchiveObjectWithData:data或者unarchiveObjectWithFile:file类方法。

      1
      2
      3
      4
      5
      6
      7
      // 归档
      NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
      [NSNumber numberWithInt:89],@"objc",
      [NSNumber numberWithInt:88],@"cpp",
      [NSNumber numberWithInt:87],@"java",
      nil];
      [NSKeyedArchiver archiveRootObject:dict toFile:@"myDict.archive"];
      1
      2
      3
      4
      5
      // 恢复
      NSDictionary* dict = [NSKeyedUnarchiver unarchiveObjectWithFile:@"myDict.archive"];
      NSLog("%d",[dict valueForKey:@"objc"]);
      NSLog("%d",[dict valueForKey:@"cpp"]);
      NSLog("%d",[dict valueForKey:@"java"]);

实现NSCoding协议

  • 自定义类要实现归档、恢复,应该实现NSCoding协议,必须实现该协议中的定义的如下两个方法
    • initWithCoder:该方法负责恢复对象
    • encodeWithCoder:该方法负责归档对象
  • 归档和恢复基本数据类型
归档数据 恢复数据
encodeBool:forKey decodeBoolForKey
encodeInt:forKey decodeIntForKey
encodeInt32:forKey decodeInt32ForKey
encodeInt64:forKey decodeInt64ForKey
encodeFloat:forKey decodeFloatForKey
encodeDouble:forKey decodeDoubleForKey
  • 示例
1
2
3
4
5
6
7
# import <Foundation/Foundation.h>
@interface ZTApple : NSObject <NSCoding>
@property (nonatomic,copy) NSString* color;
@property (nonatomic,assign)double weight;
@property (nonatomic,assign)int size;
- (id) initWithColor:(NSString*) color weight:(double) weight size:(int) size;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# import "ZTApple.h"
@implementation ZTApple
@synthesize color = _color;
@synthesize weight = _weight;
@synthesize size = _size;
-(id) initWithColor:(NSString*) color weight:(double) weight size:(int) size
{
if(self = [super init])
{
self.color = color;
self.weight = weight;
self.size = size;
}
return self;
}
-(NSString *)description
{
return [NSString stringWithFormat:"@<ZTApple[_color=%@,_weigt=%g,_size=%d]>",self.color,self.weight,self.size];
}
-(void) encodeWithCoder:(NSCode*) coder
{
[coder encodeOject:_color forKey:@"color"];
[coder encodeDouble:_weight foeKey:@"weight"];
[coder encodeInt:_size forKey:@"size"];
}
-(void) initWithCoder:(NSCoder*) coder
{
_color = [coder decodeObjectForKey:@"color"];
_weight = [coder decodeDoubleForkey:@"weight"];
_size = [coder decodeIntForKey:@"size"];
return self;
}
@end

使用NSData完成自定义归档

  • 一次性收集多个对象,并将这些对象归档到单个文件中,此时借助NSMutableData来创建NSKeyedArchiver或NSKeyedUnarchiver对象。
  • 归档过程
  1. 以NSMutableData作为参数,创建NSKeyedArchiver对象。
  2. 反复调用NSKeyedArchiver对象的encodeXxx:forKey:方法来归档所有需要归档到一个文件的对象。
  3. 调用NSKeyedArchiver对象的finishEncoding方法来结束归档。
  4. 根据需要,程序可以选择将保存归档数据的NSMutableData通过网络或输出到磁盘文件上。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithInt:66],@"objc",
    [NSNumber numberWithInt:76],@"c++",
    [NSNumber numberWithInt:86],@"java",nil];
    NSSet* set = [NSSet setWithObjects:
    @"test1",@"test2",@"test3",nil];
    ZTApple* apple = [[ZTApple alloc] initWithColor:@"红色" weight:3.4 size:20];
    NSMutableData* data = [[NSMutableData data];
    NSKeyedArchiver* arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [arch encodeObject:dict forKey:@"dict"];
    [arch encodeObject:set forKey:@"set"];
    [arch encodeObject:apple forKey:@"apple"];
    [arch finishEncoding];
    if([data writeToFile:@"multi.archive" atomically:YES] == NO)
    {
    NSLog("归档失败");
    }
  • 恢复过程
  1. 以NSData作为参数,创建NSkeyedUnarchiver对象
  2. 重复调用NSKeyedUnarchiver对象的decodeXxx:forKey:方法从文件中恢复所有归档过的对象
  3. 调用NSKeyedUnarchiver对象的finishDecoding方法结束恢复
    1
    2
    3
    4
    5
    6
    NSData* data = [NSData dataWithContentsOfFile:@"multi.archive"];
    NSKeyedUnarchiver* unarch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    NSDictionary* dict = [unarch decodeObjectForKey:@"dict"];
    NSSet* set = [unarch decodeObjectForKey:@"set"];
    NSApple* apple = [unarch decodeObjectForKey:@"apple"];
    [unarch finishDecoding];