【问题标题】:ARC autoreleases too early (?)ARC 自动发布太早(?)
【发布时间】:2013-02-08 05:59:59
【问题描述】:

我在 A 类中有一个方法调用:

GDataXMLElement *infoElement = [self getElementFromFilePath:filePath];
NSString *testStringA = [infoElement attributeForName:@"someAttribute"].stringValue;

以及B类中的方法实现:

-(GDataXMLElement*)getElementFromFilePath:(NSString*)filePath {
    NSData *xmlData = [NSData dataWithContentsOfFile:filePath];
    GDataXMLDocument *infoXMLDoc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:nil];
    NSArray *infoArray = [infoXMLDoc.rootElement elementsForName:@"test"];
    GDataXMLElement *returnElement = (GDataXMLElement*)infoArray[0];
    NSString *testStringB = [returnElement attributeForName:@"someAttribute"].stringValue;
    return returnElement;
}

B 类方法末尾的returnElement 已完美初始化,testStringB 字符串包含正确的值。 但是在A类中,InfoElement的内容没有了,testStringA为nil。

我怀疑 ARC 发布 GDataXMLDocument 太早了,并且能够通过将文档绑定到 B 类中的属性来阻止这种行为:

@property (nonatomic,strong) GDataXMLDocument *infoXMLDoc;

但我对这个解决方案有点不满意。我永远不会再使用该属性,我只需要元素来解析它一次。如果可以使用属性停止发布,是否还有一种方法可以在方法中执行此操作?我尝试了这样的 __strong 限定符:

GDataXMLDocument __strong *infoXMLDoc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];

但这并没有帮助。所以我的问题,假设 ARC 确实负责:

1.是否可以在方法中告诉 ARC 不释放对象?

2。我对这里的行为有什么不明白的地方?我现在使用 ARC 已经有一段时间了,这是我第一次被卡住。

【问题讨论】:

  • 当您说“InfoElement 的内容消失了”时,您的意思是它分配了一个GDataXMLElement,但该对象不包含您期望的内容吗?还是说是nil
  • 该代码无法编译; getElementFromFilePath() 中没有 infoElement
  • 您是否关注过the instructions for adding GData to a project,包括为库文件禁用ARC?
  • 木马,编辑了代码。 Jim,后者,分配了 GDataXMLElement,但 xml 内容为空。是的,GDataXMLNode 禁用了 ARC,否则无法编译。

标签: objective-c automatic-ref-counting autorelease gdataxml


【解决方案1】:

我无法编译,所以这只是一个有根据的猜测,但我怀疑问题在于您返回一个指向在方法内部分配和释放的对象的指针:

GDataXMLElement *returnElement = (GDataXMLElement*)infoArray[0];

如您所见,您没有分配 returnElement,因此 ARC 无法理解您需要它。当您退出该方法时,它只是释放 infoArray。 如果您复制该值(类似于 [(GDataXMLElement*)infoArray[0] copy] )它应该可以工作。

【讨论】:

    【解决方案2】:

    GDataXMLNode.h 标头说:

    由创建文档的代码决定是否保留它 因为任何引用都依赖于该文档树内的节点。

    您从getElementFromFilePath 返回的节点取决于父节点(GDataXMLDocument),但这将由 ARC 发布。您必须在某处保留GDataXMLDocument,只要您引用其中的节点和元素。这些是GDataXML* 类的语义,您必须遵循它们。

    【讨论】:

    • 谢谢!这是我怀疑的,但是最好的方法是什么?添加@property 看起来有点难看恕我直言...
    • 您可以返回文档而不是元素本身,这将暂时保留它,但这违背了您的方法的目的。否则我不太确定,除了你的方法。
    • 通常你会解析你的 GDataXMLDocument 并将它保存到一个属性中。然后,您将有更多方法对该文档进行操作并返回您感兴趣的子元素。因此,稍微更改您的内部 API 以明确该文档是您需要保留的顶级根元素周围。
    • 嗯。我将您的答案标记为正确,但仍然...... B 类的生命周期很长,并且正在从 XML 初始化自身。之后,不再需要 XML。 A 类是 B 的许多子类之一,它们都以相同的方式初始化自己,这就是为什么我试图将该逻辑放入基类中的原因。现在,只要这些类还存在,我就会携带 GDataXMLDocument。不是很满意。不过还是谢谢你的帮助!
    • 您将不得不提取所需的数据并将其放入另一个对象中。每个 XML 节点/元素都有一个对父节点的引用,并且它有一个对其父节点的引用,一直沿链向上。这就是 libxml 和 GDataXML 存储它们的表示的方式。如果您想丢弃它,您需要创建自己的域对象来保存数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2014-03-29
    相关资源
    最近更新 更多