我已将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
答案 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
。