释放声明为Objective-C属性的C类型

时间:2015-04-05 12:32:16

标签: objective-c c memory-management

我已将C类型声明为Objective-C对象的属性。我想确保我的财产被ARC正确收集垃圾。

只是多次迭代不会泄漏内存,但由于我没有找到有关该主题的正确文档,我想确认一下。

基本上,当我覆盖dealloc以释放我的C类型时,我收到一个错误,我的变量从未被分配过:

  

malloc:***对象的错误:被释放的指针未被分配***
  在malloc_error_break中设置断点以进行调试

@interface MyClass : NSObject
    @property (readonly, assign) xmlDocPtr doc;
@end

@implementation MyClass
    - (void)dealloc {
       if (_doc != NULL) {
          xmlFreeDoc(_doc);  // throwing da runtime error, see above!
       }
       NSLog(@"dealloc'ed!"); // call me please T___T
    }

    // Setting my C-type property here:
    - (instancetype)initWithFileAtPath:(NSString *)path {
       NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
       [self setDoc:htmlReadMemory([data bytes], (int)[data length], "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR)];

       if (_doc == NULL) return nil;

       NSLog(@"init'ed!");  // gets called!
       return self;
    }

    // Property setter (as suggested by DarkDust):
    - (void)setDoc:(xmlDocPtr)doc {
       if (_doc != NULL) xmlFreeDoc(_doc);
       _doc = doc;
    }
@end

2 个答案:

答案 0 :(得分:2)

由于ARC只能在Objective-C对象上运行,因此无法帮助您管理C类型。

正确管理记忆的一个重要问题始终是"谁拥有'对象?" 在Objective-C中,使用引用计数和明确的命名规则来完成这项工作。由于你没有使用C类型,你需要小心。

那么,谁在创建你的xmlDoc实例?如果它是您编写dealloc方法的同一个对象(让我们调用该类Foo),并且您只想通过属性,所有权是明确的:Foo是实例的所有者,因此需要清理它。在这种情况下,您已经在dealloc中执行了此操作(虽然您有错误;变量本身总是有一个地址,因此&_doc永远不会为NULL !)。我会使属性只读以避免任何人从外部弄乱指针(为了分配它,你需要直接访问支持变量_doc)。因此它看起来像这样:

@property(readonly, assign) xmlDocPtr doc;

...
_doc = CreateTheXMLDocInstance();
...

- (void)dealloc {
    if (_doc != NULL) xmlFreeDoc(_doc);
}

如果您确实想要使属性可写,则需要正确处理setter。同样,问题是:谁拥有该实例?如果您希望Foo对象成为唯一所有者,事情实际上非常简单。您只需要编写一个自定义setter来释放旧实例:

- (void)setDoc:(xmlDocPtr)doc {
    // Do not free if it's the same pointer.
    if (doc == _doc) return;
    // Remove old instance, if we have one.
    if (_doc != NULL) xmlFreeDoc(_doc);
    // Assign new instance.
    _doc = doc;
}

如果Foo对象不是唯一所有者,则不允许在设置器中和_doc中取消分配dealloc

答案 1 :(得分:0)

现在针对您在更新问题后引用的运行时错误:错误消息告诉您有人正在尝试释放不是malloc的返回值的地址。最有可能的是,分配给_doc的值不是有效指针,或者至少不是指向malloc返回的内存块开头的指针。这反过来意味着错误必须位于htmlReadMemory函数中的某个位置:它不会返回有效的xmlDocPtr