【问题标题】:having an NSDictionary that is always stored in an app拥有一个始终存储在应用程序中的 NSDictionary
【发布时间】:2011-03-26 22:16:24
【问题描述】:

我想在我的应用程序中拥有一个“永久”NSDictionary,从应用程序启动开始,我就可以访问其中的元素,甚至在我终止应用程序并重新启动它之后。
此 NSDictionary 需要与应用程序紧密存储。一种方法是在每次应用启动时从 Web 服务数据创建 NSDictionary,然后创建一个代表此 NSDictionary 的单例类,但我认为这不好。

NSDictionary 大约可以容纳 10-20 个对象,其中键是 NSString 或 NSDate,值是 NSArray。 NSArray 中最多有大约 50 个条目(平均可能只有 5-25 个条目)。

每当用户每移动 50-100 米时,我计划将此 NSDictionary 用作我在委托 locationManager:didUpdateToLocation:fromLocation: 内部进行的计算的一部分。

感谢您就我能做到这一点的最佳方式提出建议。

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    仅将 NSDictionary 放在单例中不会在应用程序启动之间保留它,您需要将其保存到磁盘,然后在应用程序启动时从磁盘中读取它。

    如果您在 NSDictionary 或 NSArrays 中或根本没有自定义对象(您创建的子类),则可以使用此方法保存 NSDictionary 为:

    - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag

    并从磁盘打开字典:

    - (id)initWithContentsOfFile:(NSString *)path


    但是,如果您确实有自定义对象,它们将需要符合 NSCoding 协议。您必须使用 2 种不同的方法来保存和打开它:

    NSCoding 是一个协议,所以在你的 header 中你需要将它添加到 interface 行的末尾:

    @interface myClassName : NSObject <NSCoding> {
    

    (您应该添加的唯一内容是&lt;NSCoding&gt;

    那么在你的子类的实现中,你需要添加以下方法:

    - (id)initWithCoder:(NSCoder *)decoder

    和:

    - (void)encodeWithCoder:(NSCoder *)encoder


    当您想要取消归档(/打开)您的 NSDictionary(在某处包含此类)时,将调用 initWithCoder: 方法

    encodeWithCoder: 是您的 NSDictionary 存档(/保存)时调用的名称。 您自己不会调用其中任何一个。您需要在其中添加代码:

    - (id)initWithCoder:(NSCoder *)decoder {
        if ((self = [super initWithCoder:decoder])) {
            aProperty = [[decoder decodeObjectForKey:@"aProperty"] retain];
            anotherProperty = [[decoder decodeObjectForKey:@"anotherProperty"] retain];
            aFloat = [decoder decodeFloatForKey:@"aFloat"];
        }
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder {
        [super encodeWithCoder:encoder];
        [encoder encodeObject:aProperty forKey:@"aProperty"];
        [encoder encodeObject:anotherProperty forKey:@"anotherProperty"];
        [encoder encodeFloat:aFloat forKey:@"aFloat"];
    }
    

    您需要为要存储的每个值(通常是您的类所具有的所有属性、[和实例变量])设置相似的行。请注意float 行与其他行的不同之处。

    键可以是您想要的任何字符串,只要每个属性都有自己的唯一键并且它们在两种方法之间匹配即可。我个人使用属性的名称,因为它更容易理解。


    当你真正想保存你使用的 NSDictionary 时:

    [NSKeyedArchiver archiveRootObject:myDictionary toFile:pathToMyDictionary];
    

    然后打开字典:

    NSDictionary *myDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:pathToMyDictionary];
    

    (根据您的代码,您可能需要retainmyDictionary


    要获取字典的路径(用于保存和打开),请执行以下操作:

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pathToMyDictionary = [documentsDirectory stringByAppendingPathComponent:@"myDictionary.dat"];
    

    希望对您有所帮助,如果您对此答案有任何疑问,请发表评论:)

    【讨论】:

    • 什么是 NSCoding 协议?
    • NSCoding 协议需要两种方法,一种对类的属性进行编码,另一种对属性进行解码。我将编辑我的答案。
    • 一个问题.. 你有 pathToMyDictionary.. 这个路径应该在哪里,例如?
    • 您需要获取应用程序文档目录的路径(搜索stackoverflow了解如何),然后附加文件名(例如“mydict.dat”,扩展名可以是任何内容)
    • 经过一番搜索,发现需要使用NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);它返回一个 NSArray.. 所以我只选择这个 NSArray 中的第一个路径?
    【解决方案2】:

    听起来你想要 NSUserDefaults。它存储应用偏好,但也可以用于其他数据位。它本质上是一个专用的单例字典,可普遍访问并自动保存。

    【讨论】:

    • 我不知道...我认为 NSUserDefaults 似乎不是这里的情况
    • 如果您保存应用程序状态,那么这是对用户默认值的合法使用。您对需求的描述听起来像是使用默认值的东西。
    • 如果我关闭应用程序并想再次加载它,它会将 NSDictionary 存储在 NSUserDefaults 中吗?
    • 是的,写入 NSUserDefaults 的所有内容都会在写入后立即保存,并在应用启动后立即可用。
    【解决方案3】:

    您可以使用[NSDictionary dictionaryWithContentsOfFile:foo]从 plist 文件轻松生成 NSDictionary

    如果合适,plist 可以包含在您的应用程序包中,或者您可以在首次启动时从 Web 服务中获取数据并将其写入将来加载字典的 plist。

    【讨论】:

    • 好吧,我还需要给这个 NSDictionary 写信
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多