使用[CXMLNode nodesForXPath]与命名空间映射存储器崩溃(Memory cras

2019-10-29 11:52发布

我试图分析在Objective-C一些XML,使用TouchXML库 。 该XML在根元素名称空间,所以我使用该方法在如CXMLNode对象上的TouchXML库:

- (NSArray *)nodesForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error;

我的代码使用这种方法来选择一串匹配XPath查询,然后我做一些更多的XPath查询阅读一些属性的每个节点的节点。 出于某种原因,在第二组的查询的结果pointer being freed was not allocated错误-我不能工作在哪里,这是来自哪里。

OK,这里的XML的一个片段:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
  <Placemark>
    <name>Place 1</name>
    <description><![CDATA[6-20 Luck Street Eltham 3095]]></description>
    <Point>
      <coordinates>145.151138,-37.712663,0.000000</coordinates>
    </Point>
  </Placemark>
  <Placemark>
    <name>Place 2</name>
    <description><![CDATA[The Pines Shopping Centre, Reynolds Road Doncaster East 3109]]></description>
    <Point>
      <coordinates>145.168620,-37.762135,0.000000</coordinates>
    </Point>
  </Placemark>
    <Placemark>
        <name>Place 3</name>
        <description><![CDATA[25 Main Street Greensborough 3088]]></description>
        <Point>
            <coordinates>145.102788,-37.702511,0.000000</coordinates>
        </Point>
    </Placemark>
</Document>
</kml>

所以,我读入一个CMLXmlElement这一点,那么我已经使该代码读出每个<Placemark>元素:

_locations = [NSMutableArray array];
NSDictionary *mappings = [NSDictionary dictionaryWithObjectsAndKeys:@"http://earth.google.com/kml/2.2", @"kmlns", nil];
NSError *error = nil;
for (CXMLNode *node in [element nodesForXPath@"//kmlns:kml/kmlns:Document/kmlns:Placemark" namespaceMappings:mappings error:&error])
{
    [_locations addObject:[[ONEMapLocation alloc] initWithXmlElement:(CXMLElement *)node]];
}

此代码运行没有问题。 但随后,在initWithXmlElement每个位置的对象初始化自己喜欢的:

NSDictionary *namespaceMappings = [NSDictionary dictionaryWithObjectsAndKeys:@"http://earth.google.com/kml/2.2", @"kmlns", nil];
NSError *error = nil;
_name = ((CXMLNode*)[[xmlElement nodesForXPath:@"./kmlns:name/text()" namespaceMappings:namespaceMappings error:&error] lastObject]).stringValue;
_description = ((CXMLNode*)[[xmlElement nodesForXPath:@"./description/text()" namespaceMappings:namespaceMappings error:&error] lastObject]).stringValue;
NSString *rawCoordinates = _description = ((CXMLNode*)[[xmlElement nodesForXPath:@"./kmlns:Point/kmlns:coordinates/text()" namespaceMappings:namespaceMappings error:&error] lastObject]).stringValue;
NSArray *coordinateArray = [rawCoordinates componentsSeparatedByString:@","];
_latitude = [[coordinateArray objectAtIndex:1] floatValue];
_longitude = [[coordinateArray objectAtIndex:0] floatValue];

当这段代码运行时,它成功地解析XML文档,但随后约一秒钟后用的应用程序崩溃pointer being freed was not allocated错误。 如果我注释掉那些线和设置_name_description等,以虚拟值这一切工作正常。

我也试着从XML拉出命名空间和使用的TouchXML库中的方法不与命名空间打扰,它工作正常(虽然我不会有能够在编辑XML奢侈品现实世界的情景)。

我知道,长期的,复杂的问题,可能与一帮其他可能的原因,但我绝对孤立的问题到这些半打行。

Answer 1:

万一有人来这里与本或类似的问题-这听起来像(这里所描述的问题https://github.com/TouchCode/TouchXML/issues/11 ),我刚好也经历。 它在本质上是一个EXC_BAD_ACCESS错误,因为XML文档比其子节点更早被释放,而当子节点想要的dealloc独木难支崩溃。

我没有挖太深进入TouchXML代码,但TouchXML以下变化似乎来解决这个问题,也不会导致任何内存泄漏(我在探查选中):

CXMLDocument.m:

-(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 {

        //### this is added ### fix for BAD_ACCESS on CXMLNode after releasing doc - get rid of all nodes in nodePool first to make sure they are released before the doc is released
        NSArray* allObjects = [nodePool allObjects];
        for(CXMLNode* child in allObjects)
        {
            [nodePool removeObject:child];
            [child invalidate];
        }
        //### until here ###

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

CXMLNode.h:

//### add manual dealloc function ###
-(void)invalidate; // added to prevent BAD_ACCESS on doc release ...

而在CXMLNode.m:

//### invalidate function added to be able to manually dealloc this node ###
-(void)invalidate {
    if (_node)
    {
        if (_node->_private == (__bridge void *)self)
            _node->_private = NULL;

        if (_freeNodeOnRelease)
        {
            xmlFreeNode(_node);
        }

        _node = NULL;
    }
}


文章来源: Memory crash using [CXMLNode nodesForXPath] with namespace mappings