Нужно ли инициализировать пустой вложенный массив iOS, который является частью импорта plist? - PullRequest
3 голосов
/ 10 апреля 2011

код ниже работает, но я хочу убедиться, что он правильный .Я нервничаю из-за наличия в моем словаре пустого массива, который я создаю из plist, поскольку обычно кажется, что если вы не скажете, initWithCapacity:1, то вы часто получаете ошибки памяти, когда начинаете пытаться добавлять элементы.

По крайней мере, таков мой опыт работы с NSMutableDictionary.Однако это первый раз, когда я пытаюсь реализовать вложенные объекты данных, поэтому, возможно, причина того, что этот код работает, заключается в том, что вложенный массив автоматически инициализируется, когда он импортируется как часть своего родительского словаря?

Любой ивсе комментарии приветствуются.Спасибо.

Во-первых, вот как выглядит plist, который я использую для создания своего словаря:

someData.plist

Далее, вот мой код, где яиспользуя plist для создания словаря, затем добавляем элемент в dataArray

</p> <pre><code>// 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.Так что код работает.Но опять же, я хочу подтвердить, что мне здесь не «везет», так как мой код просто работает, хотя я не инициализирую этот вложенный массив должным образом.Если это так, то я мог бы столкнуться с непредвиденными ошибками позже.

Итак, для подведения итогов, dataArray - это пустой массив внутри .plist, поэтому мне нужно как-то его инициализировать (используя, например, initWithCapacity: или что-то еще) прежде чем я смогу правильно заполнить это, или способ, которым я здесь кодирую, просто отлично?

Еще раз спасибо.

РЕДАКТИРОВАТЬ

Привет всем.Я продолжал исследовать это, чтобы найти удовлетворительный ответ.Я думаю, что, возможно, наткнулся на что-то через по этой ссылке на глубокое копирование .В его предыдущих постах о глубоком копировании был представлен некоторый код, который по сути выполняет то, что я искал выше: создать изменяемую копию словаря или массива из plist, который также имеет изменяемые подструктуры.

Однако, как упомянуто в ссылке выше, похоже, что эти методы были излишними, из-за метода CFPropertyListCreateDeepCopy, который можно вызывать с помощью вызова, такого как

testData = CFPropertyListCreateDeepCopy(kCFAllocatorDefault, [NSDictionary dictionaryWithContentsOfFile:path], kCFPropertyListMutableContainersAndLeaves);

Итак, мой вопрос, могу ли я правильно использовать CFPropertyListCreateDeepCopy, как показано выше, для достижения того, о чем я здесь спрашиваю?Другими словами, могу ли я использовать этот метод для импорта моего словаря из списка с полностью изменяемыми вложенными объектами данных?

Как я уже упоминал в одном из комментариев, я знаю, что могу создать вложенный изменяемый словарь вручную, но для сложных данных это просто не практично, и кажется маловероятным, что встроенные методы для импорта изменяемого списка не существуют.Итак, исходя из вышесказанного, похоже, что я, возможно, нашел решение, но я все еще слишком новичок в этом, чтобы сказать наверняка.Пожалуйста, сообщите.

(Примечание: я бы просто протестировал код, но, как мы выяснили, текущий SDK содержит ошибки с точки зрения возможности редактирования неизменяемых вложенных словарей, в отличие от задокументированного поведения.как и раньше, меня интересует не только то, работает ли это, но и правильно ли это )

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 10 апреля 2011
Методы

init... должны вызываться только один раз, сразу после вызова alloc или allocWithZone:. Когда программный код создает и возвращает объект или граф объектов, их методы init... уже были вызваны, поэтому отправка другого сообщения init... будет иметь неопределенные результаты. Не делай этого.

Интересно, что, несмотря на то, что документация, по-видимому, говорит (и, по общему признанию, я, возможно, пропустила где-нибудь ключевое предложение или абзац), когда вы создаете экземпляр изменяемой коллекции, читая список, любые вложенные коллекции также изменчивы. Я провёл следующий небольшой эксперимент в тестовом жгуте, чтобы быть уверенным:

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, полностью инициализированы и могут изменяться для загрузки, так что вы можете просто использовать их, как вы это делали.

EDIT

Тем не менее, после некоторого дальнейшего чтения документации, я думаю, что ОП прав, что он чувствует себя неловко, полагаясь на то, что, по-видимому, является недокументированной особенностью текущей версии 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 голос
/ 10 апреля 2011

Любой объект в словаре, созданный чтением с диска, будет правильно инициализирован.Вам не придется делать это самостоятельно.Однако, как указывает jlehr, содержимое словаря должно быть неизменным .Если вы хотите, чтобы содержимое словаря было изменчивым, вам нужно будет изменить его самостоятельно.Я понятия не имею, почему ваша программа не выдает исключение.

Я не знаю, почему вы получаете ошибки памяти, когда не используете 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, вы можете использовать его везде, где запрашивается CFDictionary при преобразовании, и наоборот.Ваш код как есть выдаст предупреждение, но вы можете подавить его, приведя словарь и вернув значения.

NSDictionary *testData = (NSDictionary*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)[NSDictionary dictionaryWithContentsOfFile:path], kCFPropertyListMutableContainersAndLeaves);
...