以下代码正常运行,但我想确保正确。我很担心在我的字典中有一个我用plist创建的空数组,因为通常看起来如果你没有,比如initWithCapacity:1
,那么一旦你开始尝试添加项目,你经常会出现内存错误
至少,这是我对NSMutableDictionary的体验。但是,这是我第一次尝试实现嵌套数据对象,所以这个代码可能工作的原因是嵌套数组在作为父字典的一部分导入时会自动初始化吗?
任何和所有评论都表示赞赏。感谢。
首先,这是我用来创建词典的plist的样子:
接下来,这是我的代码,我使用plist创建字典,然后将项目添加到dataArray
// Create a pointer to a dictionary
NSMutableDictionary *dictionary;
// Read "SomeData.plist" from application bundle
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:@"SomeData.plist"];
dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:finalPath];
// Now let's see if we can successfully add an item to the end of this empty nested array. How 'bout the number 23
NSNumber *yetAnotherNumber = [NSNumber numberWithInt:23];
[[dictionary objectForKey:@"dataArray"] addObject:yetAnotherNumber];
// Dump the contents of the dictionary to the console
NSLog(@"%@", dictionary);
// Create a pointer to a dictionary
NSMutableDictionary *dictionary;
// Read "SomeData.plist" from application bundle
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:@"SomeData.plist"];
dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:finalPath];
// Now let's see if we can successfully add an item to the end of this empty nested array. How 'bout the number 23
NSNumber *yetAnotherNumber = [NSNumber numberWithInt:23];
[[dictionary objectForKey:@"dataArray"] addObject:yetAnotherNumber];
// Dump the contents of the dictionary to the console
NSLog(@"%@", dictionary);
好的,好,简单,好。当我记录字典内容时,它显示“23”已作为数组值添加到。所以代码有效。但同样,我想确认我在这里没有“变得幸运”,即使我没有正确初始化嵌套数组,我的代码也正常工作。如果是这样,那么我可能会在以后遇到意想不到的错误。
总而言之,dataArray
是.plist中的一个空数组,所以我需要以某种方式初始化它(使用,例如dataArray
或其他),然后才能正确填充它,或者我在这里编码的方式还不错?
再次感谢。
修改
嘿所有人。为了找到满意的答案,我一直在继续研究这个问题。我想我可能偶然发现了this link on deep copying。他的previous posts on deep copying已经提出了一些基本上我正在寻找的代码:从plist创建一个字典或数组的可变副本,也有可变的子结构。但是,正如上面的链接中所提到的,由于CFPropertyListCreateDeepCopy
方法,这些方法看起来是多余的,可以通过诸如
initWithCapacity:
所以,我的问题是,我能否以所示方式正确使用testData = CFPropertyListCreateDeepCopy(kCFAllocatorDefault, [NSDictionary dictionaryWithContentsOfFile:path], kCFPropertyListMutableContainersAndLeaves);
来实现我在这里所要求的内容?换句话说,我可以使用此方法从具有完全可变的嵌套数据对象的plist导入我的字典吗?
正如我在其中一条评论中提到的,我知道我可以手动创建一个嵌套的,可变的字典,但是对于那些不实用的复杂数据,导入可变plist的内置方法似乎不太可能存在。因此,基于上述情况,看起来我可能已经找到了解决方案,但我仍然对此非常新,以便能够肯定地说出来。请指教。
(旁注:我只是测试代码,但是正如我们已经建立的那样,当前的SDK是错误的,允许你编辑不可变的嵌套字典,与记录的行为相反。所以和以前一样,我是不只是对这是否有效感兴趣,而是它是否正确)
提前致谢。
答案 0 :(得分:2)
init...
方法只应在调用alloc
或allocWithZone:
后立即调用一次。当框架代码创建并返回对象的对象或图形时,它们的init...
方法已被调用,因此发送另一条init...
消息将产生未定义的结果。不要那样做。
有趣的是,尽管文档似乎在说什么(并且不可否认我可能错过了某个关键句或段落),但当您通过读取plist创建可变集合的实例时,任何嵌套集合也都是可变的。我在测试工具中运行了以下小实验,以确保:
NSMutableDictionary *pets = [NSMutableDictionary dictionaryWithContentsOfFile:@"/tmp/Pets.plist"];
NSMutableArray *cats = [pets objectForKey:@"cats"];
[cats addObject:@"Foo"]; // EDIT: Added line I accidentally omitted earlier
NSLog(@"%@", cats);
因此,当您在plist中读取时创建的嵌套集合已完全初始化,并且可以启动,因此您可以像以前一样使用它们。
修改强>
然而,在对文档进行进一步阅读之后,我认为OP对于依赖当前版本的SDK的一个未记录的功能感到不安。例如,属性列表编程指南指出:
如果您使用加载属性列表 这个电话:
NSMutableArray * ma = [NSMutableArray arrayWithContentsOfFile:xmlFile];
ma
是一个具有不可变的可变数组 每个元素中的字典。每把钥匙 每个字典中的每个值都是 不可变的。
所以,为了安全起见,如果你需要一个嵌套的集合是可变的,你应该自己创建它。例如,我建议重写上面示例中的代码,如下所示:
NSMutableDictionary *pets = [NSMutableDictionary dictionaryWithContentsOfFile:@"/tmp/Pets.plist"];
NSArray *cats = [pets objectForKey:@"cats"];
NSMutableArray *mutableCats = [cats mutableCopy];
[pets setObject:mutableCats forKey:cats];
[mutableCats release];
然后,您可以安全地更改嵌套的可变集合:
[mutableCats addObject:@"Foo"];
答案 1 :(得分:1)
通过从磁盘读取创建的字典中的任何对象都将被正确初始化。你不必自己动手。但是,正如jlehr所指出的,contents of the dictionary should be immutable。如果您希望字典的内容是可变的,则需要自己更改它们。我不知道为什么你的程序没有抛出异常。
我不知道为什么在其他情况下不使用initWithCapacity:1
时会出现内存错误。以下代码完全有效:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:@"object1"];
[array addObject:@"object2"];
NSLog(@"%@",array);
[array release];
如果未指定容量,则阵列不会预先分配任何内存,但会在以后根据需要分配内存。
修改强>:
将NSDictionary与CFPropertyListCreateDeepCopy
一起使用是完全可以接受的。在Core Foundation中,CFPropertyList可以是CFDictionary,CFArray,CFNumber,CFString或CFData。由于NSDictionary对于CFDictionary是toll-free bridged,因此您可以在通过强制转换要求CFDictionary的任何地方使用它,反之亦然。您的代码将发出警告,但您可以通过转换字典并返回值来禁止它。
NSDictionary *testData = (NSDictionary*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)[NSDictionary dictionaryWithContentsOfFile:path], kCFPropertyListMutableContainersAndLeaves);