Странный EXC_BAD_ACCESS в тривиальной программе PDFKit - PullRequest
2 голосов
/ 11 июня 2011

Я написал этот простой метод действия, связанный с текстовым полем.
Каждый раз, когда я вводю текст в текстовое поле, выполняется поиск в PDF-файле и PDFView автоматически прокручивается до выбора:

- (IBAction) search:(id)id
{
    NSString *query = [self.searchView stringValue]; // get from textfield
    selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch]; 
    if (selection != nil)
    {
        [self.pdfView setCurrentSelection:selection];
        [self.pdfView scrollSelectionToVisible:self.searchView];
    } 
}

Проблема в том, что после 3 или 4 поисков я получаю EXC_BAD_ACCESS в строке (i).
Если я отлаживаю, я вижу, что запрос содержит NSCFString, а не NSString.
Я думаю, что этопроблема управления памятью .. а где?

enter image description here

Я повторил ту же проблему в тривиальном тестовом примере:

  @interface PDFRef_protoTests : SenTestCase {
   @private

      PDFDocument *document;

   }

  ........

 - (void)setUp
  {
     [super setUp];
     document = [[PDFDocument alloc] initWithURL: @"a local url ..."];
  }

- (void)test_exc_bad_access_in_pdfdocument
{
    for (int i =0 ;i<100; i++)
    {
        NSString *temp;
        if (i % 2 == 0) temp = @"home";
        else if (i % 3 ==0) temp = @"cocoa";
        else temp=@"apple";
        PDFSelection *selection = [document findString: temp 
                                   fromSelection:nil 
                                withOptions:NSCaseInsensitiveSearch]; 
        NSLog(@"Find=%@, iteration=%d", selection, i);
    }
}

Обновление :

1)Кажется, что это происходит также, если я использую асинхронный поиск (метод beginFindString: withOptions) каждый раз, когда я выполняю второй поиск.

2) Я обнаружил аналогичную проблему с моей в MacRuby Отслеживание проблем: http://www.macruby.org/trac/ticket/1029

3) Кажется, что если я временно отключаю сборку мусора, она работает, но память увеличивается.Я написал что-то вроде:

[[NSGarbageCollector defaultCollector] disable];
[[NSGarbageCollector defaultCollector] enable];

окружающий поисковый код

Еще одно обновление

Очень странно то, что иногда все работает.Чем я чищу и перестраиваю и проблема возникает снова.С определенной точки зрения это не на 100% воспроизводимо.Я подозреваю ошибку в PDFKit или некоторые настройки компилятора, которые мне нужно сделать

Обновление снова

Уважаемые, это кажется очень сумасшедшим.Я бы сконцентрировался на тестовом примере, который очень тривиален и легко воспроизводит проблему.Что с этим не так?Этот тестовый сценарий работает, только если я отключаю (по коду или по настройкам проекта) GC

Другое обновление

Мальчики, похоже, это ошибка, но я скачал пример с названием PDFLinker из Appleвеб-сайт (http://developer.apple.com/library/mac/#samplecode/PDFKitLinker2/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003594). В этом примере реализован PDFViewer. Код моего приложения и этот пример очень похожи. Для одного и того же поискового действия в том же PDF моя память увеличивается на 300/400 МБ, а PDFLinker - на 190 МБ.что-то не так в моем коде. Но я сравниваю это постепенно, и я не думаю, что я вставляю утечки памяти (и прибор не дает мне никаких доказательств). Может быть, есть какие-то настройки для всего проекта?

Обновление пока что Уменьшено переключение с 64-битного на 32-битное потребление памяти. Конечно, есть проблема с 64-битным и PDFKit. Кстати, EXC_BAD_ACCESS при втором поиске

РЕШЕНИЕ Важным моментом является то, что PDFKit с сборкой мусора содержит ошибки. Если я отключаю GC, все работает правильно. У меня была другая проблема, которая усложнила мой анализ:Я отключил GC в настройках проекта, но GC остался включенным в настройках цели.Так что пример Apple PDFLinked2 работал, а мой нет.

Ответы [ 5 ]

2 голосов
/ 17 июня 2011

Я согласен, что вы нашли ошибку в PDFKit.

Я получил различные формы ошибок (ошибка сегментации, селектор не понятен и т. Д.) При выполнении теста. Заключение кода в @ try / @ catch не предотвращает все ошибки, связанные с этим методом.

Я также получил ошибки при печати сообщения журнала.

Чтобы обойти ошибки, я предлагаю вам отключить GC во время вызова -findString: fromSelection :, как вы уже обнаружили.

Кроме того, обязательно сделайте копии представляющих интерес значений из selection перед повторным включением GC. Не просто скопируйте выделение .

Если вы выполняете поиск из нескольких мест в своем коде, я также предлагаю вам извлечь отдельный метод для выполнения поиска. Затем вы можете вызвать его для проведения поиска, не дублируя вложение / отключение GC.

2 голосов
/ 11 июня 2011

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

1 голос
/ 15 июня 2011

оставьте PDFSelection *selection в качестве переменной-члена и передайте ее в fromSelection: вместо nil.

Возможно, что PDFDocument сохранит возвращенный экземпляр PDFSelection для повышения производительности.

1 голос
/ 15 июня 2011

Вы пытались сохранить объект строкового значения searchview перед его использованием?

Как вы говорите, это происходит, когда вы печатаете быстро, и это происходит для асинхронных вызовов, возможно, что объект, на который указывает stringValue, освобождается между временем, на которое ваш объект query указывает на него, и временем Вы используете его в поиске.

Вы можете попробовать что-то вроде этого, чтобы увидеть, сохраняется ли проблема:

- (IBAction) search:(id)id
{
    NSString *query = [[self.searchView stringValue] retain]; // get from textfield
    selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch]; 
    if (selection != nil)
    {
        [self.pdfView setCurrentSelection:selection];
        [self.pdfView scrollSelectionToVisible:self.searchView];
    } 

    [query release];

}

Конечно, существует также вероятность того, что document передается. Как вы это объявляете? это свойство с удержанием? Может ли он быть выпущен к тому времени, когда вы ищете?

EDIT:

Я вижу, что вы отправили код со вторым параметром как NULL, но на вашем скриншоте это значение равно nil.

В документации сказано, что вы должны использовать NULL, если хотите начать поиск с начала.

http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/QuartzFramework/Classes/PDFDocument_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003873-RH2-DontLinkElementID_1

И поскольку компилятор по-разному интерпретирует nil и NULL, это может привести к некоторому странному поведению внутри.

1 голос
/ 12 июня 2011

Судя по вашему скриншоту, похоже, что у вас не включен NSZombie.Вероятно, причина, почему это не поможет вам.Вот как вы его включаете:

Как включить NSZombie в Xcode?

Скриншот, который вы предоставили, был очень полезен, но вам действительно нужно NSZombie, чтобы понятьиз такого рода ошибок.Ну, если не очевидно, что это не из кода, который вы опубликовали.


РЕДАКТИРОВАТЬ: Я прочитал комментарий, что вы используете сборщик мусора.Я разработчик для iOS, поэтому у меня очень ограниченный опыт сборки мусора в Objective-C, но, насколько я понимаю, NSZombie не работает в среде сборки мусора.

Я не уверен, что будет возможно получить EXC_BAD_ACCESS в среде сборки мусора, если вы не создадите свой собственный указатель и не попытаетесь вызвать методы на нем, не создав объект, и я не понимаю, почему высделал бы это.

Я слышал, что некоторые фреймворки плохо работают с сборкой мусора, но я не думаю, что среди них был PDFKit.В любом случае, решение может состоять в том, чтобы не использовать сборку мусора.Возможно, вам следует отправить отчет об ошибке в Apple.

...