我刚刚完成了 iOS 开发的第二个教程。当我添加新的目击时,它工作正常并出现在目击列表中。但是,当我关闭 iOS 模拟器并重新打开它时,那里只有第一个条目(它是手动添加的)。即使关闭并重新打开,iOS模拟器中是否应该有内部存储器?似乎有一些记忆,好像我将我的联系信息添加到了联系人中,当我重新打开它时它仍然存在。如果是这样,我如何确保 DataController 文件中的数组同样存储在模拟器/手机上,这样每次我重新打开模拟器时它都不会自行清除?
谢谢
我刚刚完成了 iOS 开发的第二个教程。当我添加新的目击时,它工作正常并出现在目击列表中。但是,当我关闭 iOS 模拟器并重新打开它时,那里只有第一个条目(它是手动添加的)。即使关闭并重新打开,iOS模拟器中是否应该有内部存储器?似乎有一些记忆,好像我将我的联系信息添加到了联系人中,当我重新打开它时它仍然存在。如果是这样,我如何确保 DataController 文件中的数组同样存储在模拟器/手机上,这样每次我重新打开模拟器时它都不会自行清除?
谢谢
如果要在会话之间保存数据,则需要使用持久存储。选项包括:
您可以使用 plist 文件。例如,如果您有NSArray *array
,您可以使用以下命令将其保存到 plist writeToFile
:
[array writeToFile:filename atomically:YES];
然后,您可以使用以下命令读取此数组:
NSArray *array = [NSArray arrayWithContentsOfFile:filename];
此技术仅适用于标准NSString
,NSNumber
等对象,BirdSighting
但不适用于自定义对象,例如 。
对于自定义对象,如BirdSighting
,您可以使用NSKeyedArchiver
和NSKeyedUnarchiver
。顺便说一句,这些类不仅对于保存此类小型数据集的数据通常很有用,而且鉴于它在新的 iOS 6 状态保存功能中的突出特点,因此值得您熟悉这种模式。
您可以使用NSUserDefaults
. 这确实更适合应用程序设置和默认设置,但理论上也可以用于保存数据。
您可以使用CoreData。这是对象持久化的首选 iOS 技术。它是一个功能强大且设计精良的框架(虽然有点复杂),并且非常适合您处理大量数据的情况。
您也可以使用SQLite。请参阅这篇关于使用 SQLite 的 Ray Wenderlich 文章。一旦你开始使用 SQLite,你可以考虑使用FMDB来简化你的编码工作。
例如,如果您想使用第二种方法,NSKeyedArchiver
并且NSKeyedUnarchiver
,您可能想要做的第一件事是使BirdSighting
符合NSCoding
,通过将@interface
声明更改为BirdSighting.h
:
@interface BirdSighting : NSObject <NSCoding>
其次,您必须编写两个NSCoding
方法,initWithCoder
并且encodeWithCoder
,在BirdSighting.m
其中定义可以为此对象加载/保存哪些属性:
- (NSArray *)keysForEncoding;
{
return @[@"name", @"location", @"date"];
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
for (NSString *key in [self keysForEncoding])
{
[self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
for (NSString *key in self.keysForEncoding)
{
[aCoder encodeObject:[self valueForKey:key] forKey:key];
}
}
您BirdSighting
现在可以分别用NSKeyedUnarchiver
和加载和保存。NSKeyedArchiver
因此,专注于目击事件的加载,您必须 (a) 告知BirdSightingDataController.m
要查找的文件;(b) 指示它在初始化期间读取该文件:
- (NSString *)filename
{
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
return [docsPath stringByAppendingPathComponent:@"BirdSightings"];
}
- (void)initializeDefaultDataList
{
NSString *filename = [self filename];
self.masterBirdSightingList = nil;
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
{
self.masterBirdSightingList = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
}
if (!self.masterBirdSightingList)
{
NSMutableArray *sightingList = [[NSMutableArray alloc] init];
self.masterBirdSightingList = sightingList;
BirdSighting *sighting;
NSDate *today = [NSDate date];
sighting = [[BirdSighting alloc] initWithName:@"Pigeon" location:@"Everywhere" date:today];
[self addBirdSightingWithSighting:sighting];
}
}
还可以定义一个BirdSightingDataController.m
方法来保存数据:
- (BOOL)save
{
return [NSKeyedArchiver archiveRootObject:self.masterBirdSightingList toFile:[self filename]];
}
save
例如,您现在可以在添加目击时调用此方法,例如:
- (void)addBirdSightingWithSighting:(BirdSighting *)sighting
{
[self.masterBirdSightingList addObject:sighting];
[self save];
}
就个人而言,与其在每次用户对应用程序进行任何更改时都保存它,不如让我的应用程序委托在应用程序进入后台或终止时保存它(但这需要进一步更改,所以我不会讨论现在)。
但希望这段代码说明了如何使用NSKeyArchiver
以及NSKeyUnarchiver
保存和加载数据。显然,对于更复杂的场景,我通常会鼓励您考虑 Core Data。但是对于像这样的小型数据集,这种归档模式可能很有用(正如我所说,值得熟悉,因为基本技术也用于 iOS 6 应用程序状态恢复)。