Saving, Loading, and Application States

Saving, Loading, and Application States

Archiving

Archiving类似JAVA的序列化,可以将对象保存到硬盘上,也可加载硬盘上的数据来重新创建对象。

如果一个类要支持归档,需要实现NSCoding protocol,并实现encodeWithCoder: initWithCoder:方法.

在BKItem.h中声明确认NSCoding协议。

@interface BKItem : NSObject <NSCoding>

在BKItem.m中实现这两个方法:

// archived
- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.itemName forKey:@"itemName"];
    [aCoder encodeObject:self.serialNumber forKey:@"serialNumber"];
    [aCoder encodeObject:self.dateCreated forKey:@"dateCreated"];
    [aCoder encodeObject:self.itemKey forKey:@"itemKey"];
    
    [aCoder encodeInt:self.valueInDollars forKey:@"valueInDollars"];
}

// unarchived
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    
    if (self) {
        _itemName = [aDecoder decodeObjectForKey:@"itemName"];
        _serialNumber = [aDecoder decodeObjectForKey:@"serialNumber"];
        _dateCreated = [aDecoder decodeObjectForKey:@"dateCreated"];
        _itemKey = [aDecoder decodeObjectForKey:@"itemKey"];
        
        _valueInDollars = [aDecoder decodeIntForKey:@"valueInDollars"];
    }
    return self;
}

Application Sandbox

每个应用都有自己的application sandbox,其他应用无法访问你的应用的sandbox。


Application sandbox
Application sandbox

application sandbox由以下目录组成:

directory description
application bundle 只读目录,包含应用的可执行文件以及资源文件,如图片,NIB等
Documents/ 该目录下的内容可以同步到iTunes或iCloud
Library/Caches/ 缓存目录,缓存后台服务器的资源数据,即使丢失,也可以从后台再次获取到
Library/Preferences/ application preference,会同步到iTunes或iCloud.NSUserDefaults处理此目录数据
tmp/ 临时目录,NSTemporaryDirectory指向此目录

将BKItem保存到Documents目录,在BKItemStore.m中添加如下方法:

// 返回application sandbox的Documents目录
- (NSString *)itemArchivePath{
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
    NSString *documentDirectory = [documentDirectories firstObject];
    
    return [documentDirectory stringByAppendingPathComponent:@"items.archive"];
}

NSKeyedArchiver and NSKeyedUnarchiver

利用NSKeyedArchiver将数据写到指定路径。

在BKItemStore.h中声明方法来保存数据到文件系统:

- (BOOL)saveChanges;

在BKItemStore.m中实现此方法:

- (BOOL)saveChanges{
    NSString *path = [self itemArchivePath];
    
    // 1. 创建NSKeyedArchiver实例对象;
    // 2. 调用privateItems对象(NSMutableArray)的encodeWithCoder:方法,形参是NSKeyedArchiver实例;
    // 3. 数组向其内部的每个BKItem对象,发送encodeWithCoder:消息,形参是同样的NSKeyedArchiver实例;
    // 4. NSKeyedArchiver写数据到指定路径上
    return [NSKeyedArchiver archiveRootObject:self.privateItems toFile:path];
}

什么时候来调用此方法呢?
当用户点击home键,会发送applicationDidEnterBackground:消息给App Delegate,在该方法中保存数据到文件系统。

#import "BKItemStore.h"

@implementation BKAppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    BOOL success = [[BKItemStore sharedStore] saveChanges];
    if (success) {
        NSLog(@"Saved all of the BKItems.");
    } else {
        NSLog(@"Could not save any of the BKItems.");
    }
}

在BKItemStore.m的初始化方法中,从归档文件中反序列化对象,调用NSKeyedUnarchiver的unarchiveObjectWithFile:方法。

- (instancetype)initPrivate{
    self = [super init];
    if(self){
        
        // Unarchive data
        NSString *path = [self itemArchivePath];
        _privateItems = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        
        if (!_privateItems) {
            _privateItems = [[NSMutableArray alloc] init];
        }
    }
    return self;
}

现在可以动态的创建BKItem,保存到文件系统,加载他们。修改BKItemStore.m的createItem方法,不再生成随机值:

- (BKItem *)createItem{
    //BKItem *item = [BKItem randomItem];
    BKItem *item = [[BKItem alloc] init];
    
    [self.privateItems addObject:item];
    
    return item;
}

Application States and Transitions

下图是应用的各种状态,以及状态切换时执行的方法。


Application states:

State Visible Receives Events Executes Code
Not Running No No No
Active Yes Yes Yes
Inactive Mostly No Yes
Background No No Yes
Suspended No No No

Writing to the Filesystem with NSData

利用NSData将图片写到文件系统。
在BKImageStore.m中添加如下方法,根据图片KEY返回图片路径:

// 根据指定的key, 返回图片的保存路径
- (NSString *)imagePathForKey:(NSString *)key{
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentDirectories firstObject];
    
    return [documentDirectory stringByAppendingPathComponent:key];
}

保存图片到文件系统:

- (void)setImage:(UIImage *)image forKey:(NSString *)key{
    //[self.dictionary setObject:image forKey:key];
    self.dictionary[key] = image;

    // 保存图片到文件系统
    NSString *imagePath = [self imagePathForKey:key];
    NSData *data = UIImageJPEGRepresentation(image, 0.5);
    [data writeToFile:imagePath atomically:YES];
}

删除图片:

- (void)deleteImageForKey:(NSString *)key{
    if (!key) {
        return;
    }
    [self.dictionary removeObjectForKey:key];
    
    // 删除文件系统上的图片
    NSString *imagePath = [self imagePathForKey:key];
    [[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
}

从文件系统上读取图片:

- (UIImage *)imageForKey:(NSString *)key{
    //return [self.dictionary objectForKey:key];
    //return self.dictionary[key];
    
    UIImage *result = self.dictionary[key];
    if (!result) {
        NSString *imagePath = [self imagePathForKey:key];
        
        // Create UIImage object from file
        result = [UIImage imageWithContentsOfFile:imagePath];
        
        if (result) {
            self.dictionary[key] = result;
        } else {
            NSLog(@"Error: unable to find %@", [self imagePathForKey:key]);
        }
    }
    return result;
}

NSNotificationCenter and Low-Memory Warnings

每个应用都有一个NSNotificationCenter实例。
当一个对象发送notification,notification center会转会此notification到其observer。

比如当内存过低,notification center会收到UIApplicationDidReceiveMemoryWarningNotification,可以在notification center中添加此notification的observer。

BKImageStore.m中,将其注册为UIApplicationDidReceiveMemoryWarningNotification的observer,当内存过低时,清空图片所占内存。

- (instancetype)initPrivate{
    self = [super init];
    if (self) {
        _dictionary = [[NSMutableDictionary alloc] init];
        
        // 将BKImageStore注册了内存过低notification的observer
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(clearCache:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    }
    return self;
}

- (void)clearCache:(NSNotification *)note{
    NSLog(@"flushing %d images out of the cache", [self.dictionary count]);
    [self.dictionary removeAllObjects];
}

NSNotification

除了delegation和target-action pairs,notification是另外一种回调。不过delegation和target-action paris会直接发送消息到delegate和target,notification使用middl-man: NSNotificationCenter

每个NSNotification对象都有name(notification center通过名字查找observer),object(此对象负责发送notification),可选的userInfo dictionary(包含一些poster想让observer知道的信息)。

addObserver:selector:name:object:方法的最后一个参数如果是nil,表示任何对象发送notification,observer都会收到。如果指定了某个对象,则只有当此对象发送notification时,observer才会收到notification。

同一个notification,可以有多个对象是其observer,所以当有多个对象需要响应同一个event时,就需要使用notification。

NSNotificationCenter和push/local notification没有关系。

Reading and Writing to the Filesystem

对于binary data使用NSData,文本使用NSString的两个实例方法writeToFile:atomically:encoding:error: 和initWithContentsOfFile:。除了NSString有这两个方法,NSDictionary 和 NSArray也有,不过他们写到文件系统后生成的是XML文件,而且NSDictionary 和 NSArray中的对象必须是可序列化的(property list serializable)对象:NSString, NSNumber, NSDate, NSData, NSArray, and NSDictionary.。

    NSError *err;
    
    NSString *someString = @"Text Data";
    BOOL success = [someString writeToFile:@"/some/path/file" atomically:YES encoding:NSUTF8StringEncoding error:&err];
    
    if (success) {
        NSLog(@"Error writing file: %@", [err localizedDescription]);
    }
    
    NSString *myEssay = [[NSString alloc] initWithContentsOfFile:@"/some/path/file" encoding:NSUTF8StringEncoding error:&err];
    
    if (!myEssay) {
        NSLog(@"Error reading file %@", [err localizedDescription]);
    }

注意上面代码中的err对象,开始并没有创建error对象,只是声明了一个NSError类型的变量,只有当错误发生时才需要真正创建错误对象。&err表示变量的内存地址。

UIAlertView

如果要向用户显示错误提示,可以使用UIAlertView对象。

    UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"Error" message:[err localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [a show];

The Application Bundle

在Build Phases中查看application bundle。


在app在模拟器上运行后,查看~/Library/Application Support/iPhone Simulator/ (version number)/Applications目录,可以看到application sandbox,点击 查看包内容。


可以读取application bundle中的文件,但是不能修改和添加文件:

// Get a pointer to the application bundle
NSBundle *applicationBundle = [NSBundle mainBundle];
// Ask for the path to a resource named myImage.png in the bundle
NSString *path = [applicationBundle pathForResource:@"myImage" ofType:@"png"];

本文是对《iOS Programming The Big Nerd Ranch Guide 4th Edition》第十八章的总结。


最近又被派到到JAVAEE项目了,而且开始加班,看书的时间越来越少了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知...
    莫离_焱阅读 6,505评论 1 8
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,139评论 30 470
  • 最近一朋友正准备跳槽,就从各处搜索整理一些基础,便于朋友复习,也便于自己复习查看. 1. 回答person的ret...
    smile丽语阅读 1,733评论 0 7
  • 下面是我最近两年学习OC中的一些基础知识,对于学习OC基础知识的人可能有些帮助,拿出来分享一下,还是那句话不喜勿喷...
    小小赵纸农阅读 2,579评论 1 7
  • 日暮西山近,风动鸟惊心。 寒来入延髓,落红飞絮飞。 时来夏初定,寂静无蝉鸣。 墨上心难叙,一笔一生轻。
    墨月霜花阅读 221评论 0 2