1

我刚刚完成了 iOS 开发的第二个教程。当我添加新的目击时,它工作正常并出现在目击列表中。但是,当我关闭 iOS 模拟器并重新打开它时,那里只有第一个条目(它是手动添加的)。即使关闭并重新打开,iOS模拟器中是否应该有内部存储器?似乎有一些记忆,好像我将我的联系信息添加到了联系人中,当我重新打开它时它仍然存在。如果是这样,我如何确保 DataController 文件中的数组同样存储在模拟器/手机上,这样每次我重新打开模拟器时它都不会自行清除?

谢谢

4

1 回答 1

2

如果要在会话之间保存数据,则需要使用持久存储。选项包括:

  1. 您可以使用 plist 文件。例如,如果您有NSArray *array,您可以使用以下命令将其保存到 plist writeToFile

    [array writeToFile:filename atomically:YES];
    

    然后,您可以使用以下命令读取此数组:

    NSArray *array = [NSArray arrayWithContentsOfFile:filename];
    

    此技术仅适用于标准NSString,NSNumber等对象,BirdSighting但不适用于自定义对象,例如 。

  2. 对于自定义对象,如BirdSighting,您可以使用NSKeyedArchiverNSKeyedUnarchiver。顺便说一句,这些类不仅对于保存此类小型数据集的数据通常很有用,而且鉴于它在新的 iOS 6 状态保存功能中的突出特点,因此值得您熟悉这种模式。

  3. 您可以使用NSUserDefaults. 这确实更适合应用程序设置和默认设置,但理论上也可以用于保存数据。

  4. 您可以使用CoreData。这是对象持久化的首选 iOS 技术。它是一个功能强大且设计精良的框架(虽然有点复杂),并且非常适合您处理大量数据的情况。

  5. 您也可以使用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 应用程序状态恢复)。

于 2013-05-21T22:04:22.970 回答