Reputation: 3126
I have declared a C type as a property of my Objective-C object. I would like to make sure that my property is getting garbage collected properly by ARC.
Just iterating a bunch of times doesn't leak memory, but since I haven't found proper documentation on the subject I would like to confirm.
Basically, when I override dealloc
to free my C type, I get an error my variable was never allocated:
malloc: *** error for object: pointer being freed was not allocated ***
set a breakpoint in malloc_error_break to debug
@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
Upvotes: 1
Views: 79
Reputation: 92316
Now for your runtime error you've cited after updating the question: the error message tells you that someone is trying to free an address that was not the return value of malloc
. Most likely, the value assigned to _doc
is not valid pointer, or at least not a pointer to the beginning of a block of memory that was returned by malloc
. That in turn means the error must be somewhere in your htmlReadMemory
function: it doesn't return a valid xmlDocPtr
.
Upvotes: 0
Reputation: 92316
Since ARC can only operate on Objective-C objects, it cannot help you with managing C types.
A vital question to correctly managing memory always is "who 'owns' the object?" In Objective-C, that's done using reference counting and clear naming rules to aid that. Since you don't have that with the C types, you need to be careful.
So, who is creating your xmlDoc
instance? If it's the same object for which you've written the dealloc
method (let's call that class Foo
), and you just want to expose the instance via the property, the ownership is clear: Foo
is the owner of instance and thus needs to clean it up. You're already doing that in dealloc
in this case (though you have a bug there; the variable itself always has an address, so &_doc
will never be NULL!). I would make the property read-only to avoid anyone messing with the pointer from the outside (to assign it, you'd then need to access the backing variable _doc
directly). It would thus look like this:
@property(readonly, assign) xmlDocPtr doc;
...
_doc = CreateTheXMLDocInstance();
...
- (void)dealloc {
if (_doc != NULL) xmlFreeDoc(_doc);
}
If you actually want to make the property writable, you need to correctly handle the setter. Again, the question is: who owns the instance? If you want the Foo
object to be the sole owner, things are actually pretty easy. You'll just need to write a custom setter to deallocate old instances:
- (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;
}
If the Foo
object would not be the sole owner it would not be allowed to deallocate _doc
in the setter nor in dealloc
.
Upvotes: 2