0
votes

I have a memory leak in my document based app. It launches fine, I can open or make a new document, but only one or two times, and then the app crashes. I used analyzed tool in Xcode and there are no issues.

However, Instruments reveals the memory leak, but I can't find where it lies in my code.
Using Objects Allocations, I can see my NSDocument subclass isn't released when I close the document... I don't really know if this is the intended behaviour.

Here is how I read and write the document :

-(NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    NSMutableData *d = [NSMutableData data];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
                                 initForWritingWithMutableData:d];
    [archiver encodeObject:[self machine]
                    forKey:IVPCodingKeyMachine];
    [archiver finishEncoding];
    [archiver release];
    if(outError) {
        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
                                        code:unimpErr
                                    userInfo:NULL];
    }
    return d;
}

-(BOOL)readFromData:(NSData *)data
             ofType:(NSString *)typeName
              error:(NSError **)outErro {
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
                                     initForReadingWithData:data];
    machine = [[unarchiver decodeObjectForKey:IVPCodingKeyMachine] retain];
    [machine setDelegate:self];
    [unarchiver finishDecoding];
    [unarchiver release];
    if(outError) {
        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
                                        code:unimpErr
                                    userInfo:NULL];
    }
    return YES;
}

The machine property is declared like so : @property(readonly) IVPMachine *machine; on the machine ivar and IVPMachine class conforms to NSCoding protocol. In case of new documents I have overridden -(id)initWithType:(NSString *)typeName error:(NSError **)outError; method, here the code I use :

-(id)initWithType:(NSString *)typeName error:(NSError **)outError {
    self = [super initWithType:typeName error:outError];
    if (self) {
        machine = [[IVPMachine alloc] initWithCreditAmount:2000];
        [machine setDelegate:self];
        [machine setGame:[[IVPGamesLibrary sharedInstance]
                           objectInGamesAtIndex:0]];
    }
    return self;
}

Finally in -(void)dealloc; method I release the machine ivar.

I can't figure out where the bug lies.. Isn't my document subclass instance supposed to be released when I close a document in my app ?

Any help is welcome. Thank you.

1
The error you're returning from your I/O methods is wrong. You clearly have implemented them, so it makes no sense to return unimpErr. You should return something closer to the truth; FoundationErrors.h is a good place to start (and note that those errors are in NSCocoaErrorDomain).Peter Hosey

1 Answers

1
votes

As a wild guess, did you implement -[IVPMachine setDelegate:] to retain the delegate? If so, don't do that. Delegates should be weak references, i.e., non-retaining. You own the IVPMachine, so if it owns you back, that's a circular ownership, and is what is keeping both the document and the IVPMachine alive.

More practically, dig some more in Instruments. It can tell you not only that you have leaked something, but every retention and release that has happened to it. Look through that list to find the retention that is not balanced out.