Question

I'm trying to learn objective-c (I'm very new to that) and I have issues with memory management...

I'm developing an iPad app that uses TouchXML.

I've created my class that extends CXMLDocument and does some initialisation by reading some contents and saving into properties.

Here is my code (SimpleManifest.h):

@interface SimpleManifest : CXMLDocument {
    CXMLNode *_defaultOrganization;
    NSString *_title;

    NSDictionary *dictionary;
}

@property (readonly) CXMLNode *defaultOrganization;
@property (readonly) NSString* title;

- (id) initWithPath:(NSString *)path options:(NSUInteger)options error:(NSError **)error;

@end

(SimpleManifest.m):

#import "SimpleManifest.h"
#import "CXMLNode_XPathExtensions.h"

@implementation SimpleManifest

- (id) initWithPath:(NSString *)path options:(NSUInteger)options error:(NSError **)error
{
    /*
    NSURL *theURL = [[[NSURL alloc] initFileURLWithPath:path] autorelease];
    self = [self initWithContentsOfURL:theURL options:options error:error];
    */

    NSData *data   = [NSData dataWithContentsOfFile:path];
    NSString *s = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];

    self = [self initWithXMLString:s options:options error:error];

    if (self==nil) return nil;

    // load main props

    dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                  @"http://www.imsglobal.org/xsd/imscp_v1p1", @"imscp",
                  @"http://ltsc.ieee.org/xsd/LOM", @"lom", nil];


    // defualt organization
    @try {


        CXMLNode *orgsElem = [[[self childAtIndex:0] nodesForXPath:@"//imscp:organizations" namespaceMappings:dictionary error:nil] objectAtIndex:0];
        NSString *xpath = [NSString stringWithFormat:@"//imscp:organization[@identifier='%@']", [[orgsElem attributeForName:@"default"] stringValue]];

        _defaultOrganization = [[[self childAtIndex:0] nodesForXPath:xpath namespaceMappings:dictionary error:nil] objectAtIndex:0];


        /*
        NSArray *nodes = [[self childAtIndex:0] nodesForXPath:@"//imscp:organizations" namespaceMappings:dictionary error:nil];
        NSString *xpath = [NSString stringWithFormat:@"//imscp:organization[@identifier='%@']", [[[nodes objectAtIndex:0] attributeForName:@"default"] stringValue]];
        _defaultOrganization = [[[self childAtIndex:0] nodesForXPath:xpath namespaceMappings:dictionary error:nil] objectAtIndex:0];
        */

        CXMLNode *titleElem = [[[self childAtIndex:0]
                                  nodesForXPath:@"//lom:general/lom:title/lom:string"
                                  namespaceMappings:dictionary
                                  error:nil] objectAtIndex:0];

        _title = [[titleElem stringValue] copy];

    } @catch (NSException * e){
        self = nil;
        return nil;
    }


    return self;
}
@end

Later on in another class I do:

- (BOOL) isValidSCORMLesson:(NSString*) path {
    NSString *manifPath = [path stringByAppendingPathComponent:@"imsmanifest.xml"];
    if (![[NSFileManager defaultManager] fileExistsAtPath: manifPath isDirectory: NO])
        return NO;

    SimpleManifest *manifest = [[[SimpleManifest alloc] initWithPath:manifPath options:0 error:nil] autorelease];
    NSLog(@"%@", manifest.defaultOrganization);
    NSLog(@"%@", manifest.title);

    return (manifest!=nil);
}

It gives me tons of "pointer being freed was not allocated" errors... The thing changes if I comment out the NSLog calls above or just log the manifest.title property. Project is not using ARC, so I'm sure I'm doing something wrong with memory management.

Can someone please help me understand where I'm doing wrong? Thanks!

Was it helpful?

Solution

There isn't anything obviously wrong with that code that would cause malloc errors. Best guess is that there is a bug in the CXMLDocument class/library or some mistake in the way you are using it.

Note that a "pointer being freed was not allocated" means that someone called free() (or dealloc, effectively) on a pointer to a piece of memory that was not allocated in the first place. It usually gives you a breakpoint you can set that will then give you a backtrace of exactly where it happened.

Some comments:

(1) Do not @try/@catch in that fashion. Just don't catch at all. The pattern you are using will hide any errors. Exceptions are not meant to be recoverable in iOS/Cocoa.

(2) You can create an NSString instance directly from a file; no need to load via NSData first.

(3) You should use ARC.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top