Странный сбой, если я попытаюсь выпустить CXMLDocument

Я анализирую некоторый XML с помощью TouchXML и получаю сбой -EXC_BAD_ACCESS. Путем проб и ошибок я выяснил, что если я не выпущу свой CXMLDocument (который я выделяю), то все в порядке. Вот мой код:

- (NSArray *)getLookUps {

    //Do some stuff and then...

    NSData *tempData = [NSURLConnection sendSynchronousRequest:request 
                                                 returningResponse:nil 
                                                             error:nil];



        CXMLDocument *xmlDoc = [[CXMLDocument alloc] initWithData:tempData options:0 error:nil];
        NSDictionary *mappings = [NSDictionary dictionaryWithObject:@"http://****/****" 
                                                             forKey:@"****"];

        NSLog(@"%@", [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding]);
        NSArray *orders = [[xmlDoc rootElement] nodesForXPath:@"//****:Unit" 
                                            namespaceMappings:mappings 
                                                        error:nil];

        NSMutableArray *units = [NSMutableArray arrayWithCapacity:200];

        for (CXMLElement *order in orders) {
            NSArray *nodes = [order children];
            NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[nodes count]];

            for (CXMLElement *node in nodes) {
                [dictionary setObject:[node stringValue] forKey:[node name]];
            }
            [units addObject:dictionary];
        }

        //[xmlDoc release];
    return units;
}

См. 2-ю последнюю строку, [xmlDoc release]. Я прокомментировал это, потому что если я этого не сделаю, он вылетает. Что я делаю неправильно? Спасибо.


person user635064    schedule 17.07.2011    source источник
comment
В какой-то момент вы не можете что-то сохранить или выпустить слишком много. Утечка CXMLDocument просто скрывает проблему. Что вы делаете с массивом, возвращаемым этим методом? Можете ли вы показать код, который вызывает этот метод?   -  person albertamg    schedule 17.07.2011


Ответы (4)


Вам, вероятно, нужно сохранить объект словаря, иначе он также будет выпущен, когда вы освободите синтаксический анализатор. Попробуйте изменить [units addObject:dictionary]; на [units addObject:[dictionary retain]];.

Другая идея состоит в том, чтобы установить указатель xmlDoc на автоматический выпуск:

CXMLDocument *xmlDoc = [[[CXMLDocument alloc] initWithData:tempData options:0 error:nil] autorelease];
person Suhail Patel    schedule 17.07.2011
comment
Спасибо за ответ. Я изменил его на автозапуск, и он больше не падает. Но я не понимаю, почему он падает, когда я его явно выпускаю... Если что-то еще нужно, разве он не должен был сохранить его? У меня есть много других классов, которые используют почти такой же код, и они не авторелизятся, но они не падают. В любом случае спасибо за помощь/ - person user635064; 17.07.2011
comment
Я считаю, что arrayWithCapacity и dictionaryWithCapacity создают объекты с автоматическим выпуском, поэтому они могут быть выпущены преждевременно при выпуске xmlDoc. - person Suhail Patel; 17.07.2011
comment
Извините, если это нубский вопрос, но какое отношение NSArray или NSDictionary имеют к CXMLDocument? - person user635064; 17.07.2011
comment
Что ж, из вашего вопроса неясно, действительно ли эта строка является точной точкой сбоя, но я предполагаю, что она падает, когда вы пытаетесь получить доступ к элементам внутри массива единиц или к словарю внутри массива единиц? - person Suhail Patel; 17.07.2011
comment
Нет, это работает в NSOperation, и где-то там происходит сбой, и XCode переводит меня в класс TouchXML и указывает на строку, в которой происходит сбой. - person user635064; 17.07.2011
comment
Я играл с библиотекой TouchXML только дважды, но в обоих случаях использовал метод авторелиза. Трудно объяснить, где именно он терпит неудачу, не видя всего вашего кода. - person Suhail Patel; 17.07.2011
comment
SudzC (мыльный фреймворк) использует TouchXML, и я видел такое же поведение. Однако в моем случае автовыпуск не исправил это полностью. Сбой происходит в методе Dealloc CXMLNode. Возможно, освобождение объекта документа до того, как какой-либо из его узлов (или что-то еще) будет автоматически освобождено, вызовет проблему, но это не должно иметь значения. Объекты должны иметь возможность освобождаться в любом порядке, пока каждый участник контролирует свои счетчики удержания. Там есть проблема с сохранением, и она может быть связана с TouchXML. - person Sebastien Martin; 24.10.2011
comment
Я также сталкиваюсь с такими проблемами с TouchXML. В моем коде будет работать следующее CXMLDocument * __autoreleasing refDocument = [[CXMLDocument alloc] initWithXMLString:refXML options:0 error:&error]; если я удаляю __autoreleasing, происходит сбой. Это странно. Не уверен, почему это происходит. - person arango_86; 16.06.2015

Об этой ошибке было сообщено, и она помечена как исправленная в более новых версиях библиотеки.

http://code.google.com/p/touchcode/issues/detail?id=35

Я не проверял, действительно ли это исправлено, комментарий по этому URL предполагает, что это не так.

На мой взгляд, этой библиотеки следует избегать вообще. Для приложений iOS используйте libxml2 по нескольким причинам:

  • Это проверено и испытано, насквозь
  • Это быстро и эффективно
  • Построение представления вашего XML на основе узлов может упростить кодирование, но это тратит впустую память, поскольку у вас всегда есть весь документ в памяти. Вероятно, у вас это было не раз при разборе. Вместо этого вы должны разработать свой код для работы с подходом libxml2. Вы согласитесь, как только начнете анализировать документы значительного размера.
person Sebastien Martin    schedule 24.10.2011

Я использовал TouchXML довольно часто, и (к счастью?) у меня не было этой проблемы до сих пор, но это просто произошло...

Я разместил решение здесь: Сбой памяти с использованием [CXMLNode nodesForXPath ] с сопоставлениями пространств имен

person TheEye    schedule 24.09.2013

Я заметил, что в классе TouchXML «CXMLDocument» у нас есть следующая обработка в методе «dealloc».

- (void)dealloc
{
    // Fix for #35 http://code.google.com/p/touchcode/issues/detail?id=35 -- clear up the node objects first (inside a pool so I _know_ they're cleared) and then freeing the document

    @autoreleasepool {

        nodePool = NULL;

    }
    //
    xmlUnlinkNode(_node);
    xmlFreeDoc((xmlDocPtr)_node);
    _node = NULL;
}

Я не уверен, почему мы используем «autoreleasepool» в «dealloc». Это стандартная кодировка? Поправьте меня, если я ошибаюсь.

person arango_86    schedule 16.06.2015