【问题标题】:How to save data of master detail application so that it will load after application?如何保存主从应用程序的数据,以便在应用程序后加载?
【发布时间】:2013-05-15 08:14:52
【问题描述】:

我已经对这个主题进行了长期而艰苦的研究,但找不到解决方案。我对 xcode 中的 iphone 应用程序开发非常陌生,所以请让答案易于理解,哈哈。我按照苹果的“你的第二个 iOS 应用程序”教程,让主细节应用程序完美运行,但现在我想保存用户输入的数据,以便在重置应用程序后显示。代码与苹果教程here上的代码相同

提前致谢!

【问题讨论】:

    标签: ios load save master-detail


    【解决方案1】:

    您需要做出两个主要决定:如何存储数据,以及何时存储/检索数据。让我们从如何存储数据开始。

    如何存储数据

    您可以采用三种主要方法:保存到文件、保存到 SQLite 数据库(带有或不带有 FMDB 等包装器),使用 CoreData。最终你会想要掌握 SQLite 和 CoreData,但现在我建议采用第一种方法。

    如果您要保存到文件/从文件中读取,您需要确定格式。有许多不同的选项,包括 XML、JSON、您自己的自定义格式等。事实上,对于“真实”项目,根据项目目标,JSON 等格式可能是一个不错的选择。但是,我将讨论使用序列化存档,因为很多机制已经到位。

    要将数据存储在存档中,您将使用 NSKeyedArchver 将数据写入文件。稍后,您将使用 NSKeyedUnarchiver 从文件中检索信息。这些类将您的数据编码/解码到/从字节流中,然后可以通过网络发送,写入文件等。

    您的主要数据结构是名为 masterBirdSightingList 的 NSMutableArray,因此归档器需要对数组进行编码。 NSArray 及其可变对应物已经知道如何对自己进行编码/解码:它们只是对每个元素以及一些簿记信息进行编码/解码。所以这个谜题缺少了一块。您需要指定如何编码/解码 BirdSighting 类的实例。

    要指定这一点,您需要修改类以使其实现 NSCoding 协议。在 BirdSighting.h 中,将 @interface 声明更改为

    @interface BirdSighting : NSObject <NSCoding>
    

    实现 NSCoding 很简单。我在上面提到了各种数组类知道如何自己编码/解码,即它们已经实现了 NSCoding 协议。要对 BirdSighting 进行编码/解码,我们只需要对类的每个数据成员进行编码/解码。查看源代码,我看到它们是两个 NSString 和一个 NSDate。但是这些类中的每一个也已经实现了 NSCoding。因此,为了对 BirdSighting 实例进行编码/解码,我们只需要告诉每个实例变量自己进行编码/解码。我们在您添加到 BirdSighting 类的方法 initWithCoder:encodeWithCoder: 中完成所有这些工作。

    注意:我要掩饰的细节之一是归档器和键控归档器之间的区别。通常,您需要使用键控存档器,因此需要三个宏定义。老实说,我会创建 NAME_KEY 等,作为静态 NSString 常量而不是宏。

    #define NAME_KEY @"name"
    #define LOCATION_KEY @"location"
    #define DATE_KEY @"date"
    
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super init]; 
        if (self) {
           _name = [aDecoder decodeObjectForKey:NAME_KEY];
           _location = [aDecoder decodeObjectForKey:LOCATION_KEY];
           _date = [aDecoder decodeObjectForKey:DATE_KEY];
        }
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
       [aCoder encodeObject:self.name forKey:NAME_KEY];
       [aCoder encodeObject:self.location forKey:LOCATION_KEY];
       [aCoder encodeObject:self.date forKey:DATE_KEY];
    }
    

    还有一点需要注意,因为 BirdSighting 直接继承自 NSObject(它没有实现 NSCoding),所以我使用 self = [super init]。如果父类确实实现了 NSCoding,你会想做self = [super initWithCoder:aCoder]

    有了上述内容,保存到文件/从文件中读取就很容易了。在 BirdSightingDataController 的某处,可能在 initializeDefaultDataList 中,我们插入以下内容:

    masterBirdSightingList = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    

    其中 path 是一个 NSString,其中包含存档文件的目录路径以及在生产代码中需要进行错误检查和处理的常见警告(例如,如果文件不存在怎么办)。

    保存数据也很容易。我们可以在 BirdSightingDataController 对象中添加如下方法:

    - (BOOL)archiveToPath:(NSString *)path
    {
        BOOL success = [NSKeyedArchiver archiveRootObject:self.masterBirdSightingList];
        return success;
    }
    

    何时存储数据

    现在我们已经有了保存和恢复数据的代码,我们需要决定何时执行这些操作。在这里,我会稍微含糊一些,因为其他问题,例如整体应用程序结构,也会发挥作用。但是,由于与在后​​台运行相关的方法(例如 applicationWillResignActive:applicationWillEnterForeground:.

    在进入后台之前删除目击列表的内存副本是一件好事。这建议将用于创建存档的代码放在应用程序委托中。相反,您应该考虑延迟加载列表,即在您准备好显示它之前不要检索它,这建议将检索列表的代码放在 BirdSightingDataController 的 init 方法中。

    现在您的挑战是在不过度耦合和过度复杂化您的应用的情况下完成所有这些工作。但我会把这个讨论留给另一个问答环节。

    【讨论】:

    • 首先,非常感谢您的深入回复。其次,xcode 接受除了 archiveToPath 方法之外的所有代码,它说“选择器'archiveRootObject'没有已知的类方法”和“指向整数转换的不兼容指针初始化'BOOL'(又名'signed char')类型的表达式' id';"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 2015-12-13
    • 2016-06-16
    • 2013-09-21
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多