Управление памятью Objective C, xml синтаксический анализатор и другие нетривиальные примеры

Я думаю, это должно быть сделано:

SELECT *
FROM users
WHERE privacy = 0
AND id <> 3
AND id NOT IN (
    SELECT receiver_id FROM friends WHERE sender_id   = 3
    UNION ALL
    SELECT sender_id   FROM friends WHERE receiver_id = 3
)

Предполагается, что sender_id и receive_id не могут содержать NULL.

7
задан eddie 27 January 2017 в 15:02
поделиться

6 ответов

1-й вопрос - повторения и временные присвоения

Вы не должны выпускать объекты здесь, так как Вы не владелец. Необходимо только когда-либо выпускать объект, если Вы - владелец его. См. Руководство по управлению памятью для Какао. Вы - только владелец объекта при вызове метода, имя которого начинается init, new, или содержит copy на его имя.

Начиная с для цикла не использует методы ни с одним из тех имен, Вы не владелец, таким образом, Вы не ДОЛЖНЫ выпускать объекты. Это приведет к освобождению объектов, прежде чем они будут сделаны, который почти наверняка приведет к повреждению памяти и катастрофическому отказу.

2-й вопрос - момент сохраняет:

Вы не должны немедленно звонить, сохраняют, просто необходимо назвать его перед пулом автовыпуска следующая порожняя тара. Это, вероятно, будет вскоре после того, как Ваш метод возвращается к основному циклу событий. Так как Вы не знаете точно, когда это произойдет, необходимо удостовериться это, если Вы хотите смочь получить доступ к объекту после функции (loadXMLButtonClicked: в этом случае), возвраты, затем Вы должны retain это перед возвратом.

С тех пор decodeObjectForKey не начинается init или new или содержите copy на его имя Вы не становитесь владельцем. Вызов retain делает Вас владельцем.

3-й вопрос - автовыпускающие и передающие переменные:

В первую очередь, это - плохая практика к тени участник класса с локальной переменной того же имени. Во-вторых, если loadData используется в качестве многоцелевой служебной функции (который я предполагаю, что это не, так как это не берет параметров), это должно просто присвоить результат непосредственно членской переменной objectArray. Это бессмысленно и подвержено ошибкам для возврата, результат и затем иметь функцию вызова присваивают членской переменной.

В-третьих, Вы не используете objectArray метод set свойства - Вы просто присваиваетесь прямо к членской переменной. Если Вы хотите использовать метод set, необходимо явно сказать self.objectArray = ...self. перед ним). Таким образом, objectArray никогда не сохраняется, таким образом, это будет освобожденным в следующий раз, когда пул автовыпуска убирает себя, который не является тем, что Вы хотите. Необходимо сохранить его в какой-то момент, или с другой стороны, просто не автовыпускайте его в конце loadData, и присвойте ему членскую переменную класса objectArray.

Если свойство объявляется с retain атрибут, затем с помощью метода set будет автоматически звонить retain когда Вы присвоитесь с ним (и это будет также release старое значение). Если вместо этого свойство объявляется с copy атрибут, затем значение будет вместо этого скопировано каждый раз, когда Вы присваиваете ему, и Вы станете владельцем нового объекта.

4-й вопрос - синтаксический анализатор xml лучшая практика:

Вы делаете мелкую копию объектного массива. Если Вы хотите сделать глубокую копию, можно использовать initWithArray:copyItems: сообщение.

я имею к init currentObject.name (NSString) здесь? я предполагаю нет?

Я не понимаю этот вопрос, существует нет currentObject.name упомянутый вообще где угодно поблизости тот код.

почему currentChars retainCount = 2 здесь?

Вероятно, потому что во время его внутреннего процесса инициализации, это было retainредактор дополнительное время где-нибудь, но это было также почти наверняка autoreleased дополнительное время также. Если Вы будете следовать всем правилам от Руководства по управлению памятью для Какао, то у Вас не будет проблем. Вы никогда не должны полагаться, сохраняют количества, так как Вы не знаете, сколько раз был автовыпущен объект. Они - помощь для отладки, не что-то, что должно использоваться для потока программного управления.

это в настоящее время - мое решение, потому что нет никакой утечки, но я чувствую, что это неправильно?

Если Вы не должны будете использовать currentChars в следующий раз Вы возвращаетесь к циклу событий, затем он прекрасен. Если необходимо будет использовать его, Вы не должны выпускать или автовыпускать его здесь и затем выпускать его, когда Вы уверены, что сделаны с ним.

я должен скопировать здесь или просто addObject, это сохраняет так или иначе?

Просто addObject: когда Вы добавляете объекты в NSArray, NSSet, или NSDictionary, они автоматически retainредактор по условию структура. Когда Вы удаляете их, они released.

Большей частью остальной части вопросов можно ответить только после правил или иметь идентичные ответы на некоторые предыдущие вопросы, на которые я уже ответил.

7
ответ дан 7 December 2019 в 05:30
поделиться

Вопрос о @1st

Вы только получаете ссылку на объект в objectArray. Все еще в objectArray также сохранили объект, и выпуск его не хорош здесь, потому что Вы не сделали ничего, что сохранило его.

Посмотрите здесь для некоторых правил

1
ответ дан 7 December 2019 в 05:30
поделиться

Вопрос о @2nd

Похож на Вас, устанавливают текстовое свойство UILabel, которое в этом случае использует копию. В документации это говорит:

@property(nonatomic, copy) NSString *text;

Это означает, что Маркировка скопирует и сохранит ту копию, не изменяющуюся, или сохраняющую объект раньше присваивал свойство.

0
ответ дан 7 December 2019 в 05:30
поделиться

Вопрос о @3rd

Строка"objectArray = [self loadData]; // 1 - objectArray is instance var"не действительно метод set, поскольку он получает доступ к переменной экземпляра непосредственно. Для использования метода set, нужно получить доступ к нему хотя сам

self.objectArray = [self loadData];

... и если Ваше свойство объявляется как (nonatomic, copy) старый objectArray будет выпущен, и новое будет создано с копией, таким образом будучи сохраненным.

0
ответ дан 7 December 2019 в 05:30
поделиться

Благодаря всем для ответов. Те ответы помогли, хотя в немногих местах только, остальные я должен был выяснить меня. Я намного больше фокусировался на идее, не линию за линией реализации, но было трудно описать здесь, не вставляя огромные блоки кода. Это просто, что делегат к парсингу объекта XML является очень определенным примером, потому что это не возвращает значение по сути, значение должно быть принято и присвоено внешне.

Я отмечаю ответ Adam так же лучше всего один, как являющийся наиболее подробным, даже при том, что, не отвечая на все мои проблемы.

Для других - http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html является превосходным чтением. Также прочитайте мои собственные ответы на вопросы:

1 - Конечно, я не должен выпускать тот объект. Утечка памяти не была вызвана этим.

2 - Этот метод является ничем специальным, он просто возвращает плоскость автовыпущенный объект, поскольку другие пытались объяснить мне здесь. Корень моих начальных проблем был то, что я ранее не имел, которые сохраняют, но названный [образцовый выпуск] вскоре после, вызывая выпуск отправки пула автовыпуска к несуществующему объекту. Я не должен делать [образцового выпуска], потому что я не владелец того объекта. На самом деле это сохраняет, здесь даже не необходим, потому что мне просто нужен объект получить значение от него, и затем я могу перегрузить его, таким образом, это может быть безопасно передано для автовыпущения пула, без сохраняют.

3 - Я предназначил этот метод (loadData), чтобы быть независимым, поэтому не установив переменных экземпляра, но возвратив массив для других. Это был параллельный пример, не то, чтобы у меня есть две переменные с тем же именем в методе.

Если я объявляю объект в рамках этого метода (ситуация № 2), то именно так это происходит, что это автовыпущено в конце этого метода, потому что после того, как это заканчивается, управление возвращается к приложению, и пул выпуска умирает. Это согласилось со мной в этом примере, потому что мне не нужен массив позже. В реальном мире я должен, вероятно, иметь переменную экземпляра (ситуация № 1) и затем пойти с self.objectArray = [сам loadData], потому что это запустит метод set, и автовыпущенный объект будет сохранен для меня здесь.

4 - Я перепутал немного вещей здесь. В основном я пытался кодировать в objecive-c с ручным управлением памятью, но все еще имел отношение "сборщика"мусора"". Очень важно помнить, что, если Вы делаете [[объектное выделение] init] и затем в более позднее время [объектный выпуск] - не должно автоматически случаться так, что объект будет уничтожен! Выпуск не аннулирует! Это - конечно, фундаментальное правило (сохраняют/выпускают), но даже знание его, легко забыть. Дорожка, что Вы делаете со своим объектом между теми двумя строками - объект, может на самом деле жить в течение долгого долгого времени после, потому что "кто-то" еще станет его владельцем. Метод выпуска в конце этого класса livecycle не означает - объект теперь уничтожается, но средства: "Я больше не забочусь, мои руки являются чистыми"

Так, линию за линией:

objectArray = [[parserDelegate objectArray] copy]; 

Это прекрасно подходит, я не глубоко копирую. Я копирую массив, что означает, что он выделяет новую память для объекта массива, но не для содержания. НО, копия, отправленная в objectArray также, отправляет, сохраняют к каждому объекту. В моем примере я выпускаю свой parserDelegate, который также выпускает его собственный objectArray, уменьшаясь retainCount для каждого объекта. Если я не сделал бы копии здесь, объекты достигнут retainCount = 0 и уничтожаются. Таким образом, у меня есть новый массив с указателями на старые объекты, но они по существу становятся моими объектами, потому что предыдущий массив уничтожается, и из-за моего сохранять, я становлюсь владельцем. Извините, если это говорит немного слишком много, но я действительно должен был сфокусироваться для понимания этого.

else if ([elementName isEqualToString:@"name"]) {
    // do i have to init currentObject.name (NSString) here? i guess not?
    [self setParseChars:YES]; // just set the flag to make parse control easier
}

Вопрос здесь был к, должен ли я инициализировать свойство currentObject.name NSString, потому что это будет заполнено вскоре после того, как foundCharacters умрет. Теперь это интересно. При инициализации целого объекта его свойства NSString являются нолем. Теперь, позже, я делаю

currentObject.name = currentChars;

Который запускает метод set. Этот метод set определяется как (неатомарный, сохраните), что означает, что новое значение сохраняется, старое значение выпущено, и указатель присвоен. Достаточно забавный, не имеет значения, если предыдущее значение будет инициализировано или будет нолем - если это будет инициализировано, то это будет выпущено так или иначе, если это будет ноль, затем ноль может все еще принять выпуск (хотя я не на 100% уверен в нем?) - ничего не произойдет. Но ради правильности, я предполагаю, что начальная строка должна быть похожей:

else if ([elementName isEqualToString:@"name"]) {
    currentObject.name = [NSString new]; // just alloc/init routine
    [self setParseChars:YES]; // just set the flag to make parse control easier
}

Теперь:

[currentChars autorelease];

Не должен ли быть. Это путает дизайн, и это была плохая фиксация. Все, чем это должно быть там, просто строка init.

[objectArray addObject:[currentObject copy]];

Копия является ненужной здесь. addObject сохранит так или иначе. Никакой смысл в создании другого выделения. Это было моей из причин моих утечек.

Все остальное прекрасно. Поскольку я выпускаю currentChars право после устанавливания значения к моему объекту, он теперь сохраняет его и становится владельцем, и я просто выпускаю его "здесь" в синтаксическом анализаторе, потому что мне больше не нужен он (Это будет выделено в следующем цикле).

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

0
ответ дан 7 December 2019 в 05:30
поделиться

Static Analyzer

In addition to: Memory Management Programming Guide for Cocoa , Static Analyzer is an indispensable tool.

Project->Project Settings->Build->Build Options->Run Static Analyzer

Make sure that it is ticked.

It will tell you all memory allocation errors you are doing. So, you will understand better how to create objects, double-autorelease errors, double-release errors, referring to released objects, etc.

I read the memory management principles many times but did not get it until I used the Static Analyzer.

Now I am better at this and get it right most of the time. Static Analyzer, however, is still essential because it points out mistakes and missed ones.

Yoichi

0
ответ дан 7 December 2019 в 05:30
поделиться