Xcode - EXEC_BAD_ACCESS при объединении большой строки - PullRequest
3 голосов
/ 04 мая 2010

Я получаю EXEC_BAD_ACCESS при объединении большой строки.

Я прочитал из фида и для создания своего веб-просмотра я строю свою строку как:

NSString *pageData = @"<h1>header</h1>";

pageData = [pageData stringByAppendingFormat@"<p>"];
pageData = [pageData stringByAppendingFormat@"self.bodyText"];
pageData = [pageData stringByAppendingFormat@"</p>"];
etc

У меня проблема с self.bodytext - это 21 089 символов с пробелами, когда я рассчитываю на слово Есть ли лучший способ сделать это?

Спасибо

Ответы [ 4 ]

6 голосов
/ 04 мая 2010

Вы определенно хотели бы использовать NSMutableString для чего-то вроде этого:

NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

[pageData appendFormat:@"<h1>header</h1>"];
[pageData appendFormat:@"<p>"];
...

NSMutableString разработан для этого вида последовательной конкатенации, где базовый класс NSString действительно не предназначен для использования таким образом. Ваш исходный код будет фактически выделять новую строку NSSt при каждом вызове stringByAppendFormat:, а затем приступать к копированию в него всех тысяч символов, которые вы уже добавили. Это может легко привести к ошибке нехватки памяти, так как размер временных строк будет расти по экспоненте, когда вы добавляете все больше и больше вызовов.

Использование NSMutableString не приведет к повторному копированию всех строковых данных при вызове appendFormat:, поскольку изменяемая строка поддерживает внутренний буфер и просто прикрепляет новые строки к его концу. В зависимости от размера вашей строки, вы можете заранее зарезервировать огромный кусок памяти (используйте значащее число для аргумента ...WithCapacity:). Но нет необходимости идти по этому пути, если вы не столкнетесь с проблемами производительности.

2 голосов
/ 05 мая 2010

Есть несколько проблем с вашим примером кода:

  1. Вы должны использовать NSMutableString для создания выходной строки путем добавления нескольких частей. NSString - это неизменяемый класс, который означает, что каждый раз, когда вы вызываете stringByAppendingFormat:, вы сталкиваетесь с дополнительными затратами на создание дополнительного нового объекта NSString, который необходимо будет собирать и освобождать пулом автоматического выпуска.

    NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

  2. Вы должны использовать appendString: на вашем NSMutableString для добавления контента, вместо stringByAppendingFormat: или appendFormat:. Методы формата предназначены для создания новых строк на основе спецификатора формата, который включает в себя специальные поля в качестве заполнителей. См. Форматирование строковых объектов для получения более подробной информации. Когда вы используете stringByAppendingFormat: только с литеральной строкой, как в вашем коде, вы несете накладные расходы на синтаксический анализ строки для несуществующих заполнителей, и, что более важно, если строка содержит заполнитель (или что-то такое, что Похоже на то, что в нем вы получите крах EXEC_BAD_ACCESS, который вы получаете. Скорее всего, это происходит при добавлении вашего bodyText. Таким образом, если вы просто хотите добавить '

    ' к вашему NSMutableString, сделайте что-то вроде этого:

    [pageData appendString:@"<p>"];

  3. Если вы хотите добавить содержимое свойства self.bodyText в строку, вы не должны помещать имя свойства внутри строкового литерала (т. Е. @ "Self.bodyText" является литеральной строкой «self.bodyText», а не содержимое свойства. Попробуйте:

    [pageData appendString:self.bodyText];

В качестве примера, вы могли бы фактически объединить все три строки вашего примера кода, используя спецификацию формата:

pageData = [pageData stringByAppendingFormat:@"<p>%@</p>", self.bodyText];

В спецификации формата %@ - это заполнитель, который означает вставку результата отправки сообщения description или descriptionWithLocale: объекту. Для NSString это просто содержимое строки.

1 голос
/ 04 мая 2010

Используйте appendString: вместо appendFormat: при работе с произвольными строками.

pageData = [pageData stringByAppendingString:@"<p>"];
pageData = [pageData stringByAppendingString:@"self.bodyText"];
pageData = [pageData stringByAppendingString:@"</p>"];

или не используйте произвольную строку в качестве формата:

pageData = [pageData stringByAppendingFormat:@"<p>%@</p>" , @"self.bodyText"];

Если вы строите строку по частям, используйте NSMutableString вместо нескольких вызовов stringBy.

Помните, что% - это специальный символ для форматированных строк и для экранирования URL, поэтому, если bodyText содержит URL, это может легко вызвать сбой.

1 голос
/ 04 мая 2010

Я сомневаюсь, что длина строки действительно проблема.Строка из 50 000 символов занимает всего около 100 КБ.Но вы хотите быть очень осторожными в использовании строк формата.Если ваша строка содержит что-то, похожее на спецификатор форматирования, лучше иметь соответствующий аргумент, иначе вы получите мусор, если вам повезет, и вылет, если нет.Я подозреваю, что это ошибка, так как нет другой очевидной проблемы из вашего описания.Будьте осторожны с тем, что вы там указали, и никогда не помещайте динамический текст в строку формата - просто введите %@ в строку формата и передайте динамический текст в качестве аргумента.

...