Plists、数组和字典元素之间有什么关系?

5

我有一个简单的程序,需要记录并持久存储每次用户在表格视图中选择项目时产生的两个简单数据。这两个数据是1)点击时间(NSDate)和2)被点击项目的名称(NSString)。目前,这些信息呈现的形式如下:

TimerEvent *latestTappedEvent = [[TimerEvent alloc] init];
latestTappedEvent.timeTapped = NSDate.date;
latestTappedEvent.activityTapped = tappedItem.itemName;

这两个数据必须保持关联。
我的问题是:
如何将这些数据按时间顺序存入和读取自一个 plist 文件?
经过我的调查,我越来越迷惑了。我不知道如何使用 plist 文件。起初,我认为我可以使用一个 NSMutableDictionary ,以 latestTappedEvent.timeTapped 作为键,latestTappedEvent.activityTapped 作为值。但当我试图手动构建 plist 文件时,它似乎不可能,并且需要用字符串作为键。
如果有人能帮我理解这个问题,最好是通过给出这些不同元素之间关系的图形表示,我将永远感激不尽。

为什么不将您实例化的 TimerEvent 对象存储到某个集合中,而不是单独存储 .timeTapped.activityTapped - nhgrif
你使用了setValueForKey还是setObjectForKey?它们是不同的... - Wain
1个回答

2

字典和数组都存储“东西”- 存储的东西是通过使用“其他东西”在数据结构上进行“查找”来检索和设置的。在数组中,该查找是存储对象的数组索引。以表格形式表示:

Index       Storage

0           "some string stored at index 0"

1           "some other string"

2           <some other object, stored at index 2>

要查找存储在索引0处的“某个字符串”,您需要知道它存储在索引0处,并向数组请求该索引处的对象。因此,数组使用整数来查找其中存储的对象,这些整数必须在0到数组计数减1的范围内。在数组中使用整数查找项目还给数组提供了顺序 - 您在上面表格中看到的自上而下的顺序是代码迭代产生的相同顺序。
字典使用任意对象进行查找,这也意味着字典中没有顺序,只有一组键和它们所引用的内容的关联。以表格形式表示:
Key         Storage

"name"      "a string that will be accessed using the key 'name'"

"number"    <some numeric object, that will be accessed using the key 'number'>

<object>    "will be accessed with key <object> which is an arbitrary object"

要从这个字典中获取使用键“name”访问的字符串,您需要请求存储在键“name”下的内容。
在上面的例子中,我给出了表格标题“索引-存储”或“键-存储”,但为了回到这些结构都存储使用另一件事情访问的东西的观点,让我们用一个更通用的表来查看数组:
Thing used to access the thing that's stored        Thing that's stored

0                                                   "some string stored at index 0"

1                                                   "some other string"

2                                                   <some other object, stored at index 2>

再次使用相同的表格,我们来看一下字典:

Thing used to access the thing that's stored        Thing that's stored

"name"                                              "a string that will be accessed using the key 'name'"

"number"                                            <some numeric object, that will be accessed using the key 'number'>

<object>                                            "will be accessed with key <object> which is an arbitrary object"

此外,让我们将您的类TimerEvent也放在同一个表格中查看:
Thing used to access the thing that's stored                Thing that's stored

timeTapped                                                  <date object>

activityTapped                                              "name of an activity"

左列中的项目是Objective-C属性名称,右列中的项目是这些属性包含的值。现在,请再次查看字典 - 左侧的项目是任意值(实际上它们通常是字符串),右侧的项目是其他任意值。希望您可以看到这里的联系 - 您通常可以将对象的属性表示为将属性名称的字符串表示映射到属性存储的值的字典。因此,如果您想在字典中表示TimerEvent对象,则最终会得到以下表示形式:
Key                 Object

"timeTapped"        <date object>

"activityTapped"    "activity name"

上面的表格说明了数组、字典和其他对象之间的共同点和差异,并展示了使用字典将属性名映射到属性值可以表示任何给定对象的属性。那么,如何编写代码来实现这一点呢?假设我们想要在NSDictionary中表示TimerEvent对象timerEvent:
NSDictionary *timerEventRepresentation = @{ @"timeTapped": timerEvent.timeTapped,
                                            @"activityTapped": timerEvent.activityTapped};

以下是我们如何从字典表示中创建一个TimerEvent

TimerEvent *timerEvent = [[TimerEvent alloc] init];
timerEvent.timeTapped = timerEventDictionaryRepresentation[@"timeTapped"];
timerEvent.activityTapped = timerEventDictionaryRepresentation[@"activityTapped"];

将所有对象强制转换为字典的目的是属性列表格式仅序列化少数类 - NSArrayNSDictionaryNSStringNSDateNSNumberNSData。因此,我们编写代码使用支持的类来表示不支持的类,反之亦然,以便在属性列表中序列化这些对象。
补充一下,您提到需要存储所有点击记录并对其进行排序。如上所述,数组固有地对其存储的内容进行排序,因此这是适当的解决方案。您需要构建类似于以下内容的东西:
Index        Item
0            <dictionary representing first tap>
1            <dictionary representing second tap>
...
n            <dictionary representing n-1th tap>

在代码中,对每个tap进行序列化的形式与之前描述的相同,但要确保添加一个额外的步骤,即在一个NSMutableArray属性上调用addObject:方法,并将新创建的字典作为参数传递进去。

非常感谢你详尽而详细的解释,Carl!我正在消化并尝试实现。顺便说一下,我将使用NSMutableDictionary,每次用户点击新活动时都会更新它,并在退出时将内容写入plist,然后读取回来以添加更多条目。 - rattletrap99
@TimJones 不用谢。如果使用 NSMutableDictionary,原则是相同的 - 只是你需要像这样做:mutableTimerEventRepresentation[@"timeTapped"] = timerEvent.timeTapped; mutableTimerEventRepresention[@"activityTapped] = timerEvent.activityTapped;,而不是每次创建一个新的字典。 - Carl Veazey
@Carl--仍然困扰我的是:由于每次点击都会创建一个新的timerEvent,如果它们都有相同的标识符,如何区分它们之间的差异呢?"timeTapped"的值对于每个条目都是唯一的,但是"activityTapped"的值可以(并且会)变化,因此多个条目可能具有相同的"activityTapped"值。我在这里的观点是,我需要能够根据这两个属性来检索和排序。 - rattletrap99
@TimJones 如果您需要存储多个实例,则需要在可变数组中使用多个字典,每次点击都添加一个新的字典 - 而不是可变字典。就像您的对象每个属性一次只能有一个值一样,所以字典每个键也只能有一个值。 - Carl Veazey
@Carl--我得去试一下。我的右脑思维方式可能会阻碍我理解其他人觉得很简单的概念。再次感谢你的耐心! - rattletrap99
@TimJones 我对你的特定情况进行了一些小修改,以便更详细地阐述。 - Carl Veazey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接