0

I'm using TouchXML to parse an element in iOS. I retrieve a response from a web service using an NSInvocationOperation, then parse and display the results. Everything works fine as the background thread displays results on the main thread using [self performSelectorOnMainThread:@selector(displayLoginresult:) withObject:res waitUntilDone:NO]; but then I get an error:

2011-07-18 11:58:06.108 billsApp[873:7107] *** -[CFString release]: message sent to deallocated instance 0x5d809b0

The code to parse the element is:

-(LoginResult *) tryLogin:(NSString *)userName withPassword:(NSString*)password{
    NSURL *url = [UrlUtility TryLogin:userName passwordHash:password];
    CXMLDocument *responseObj = [UrlUtility xmlDocWithUrl:url];
    if(responseObj == [NSNull null])
        return [NSNull null];

    CXMLElement *eleUser = [responseObj nodeForXPath:@"//User" error:nil];
    CXMLElement *eleResult = [responseObj nodeForXPath:@"//Result" error:nil]; 
    LoginResultType resultType;
    //NSLog(@"Result: ");
    //NSLog(eleResult );
//  NSLog([[eleResult stringValue] lowercaseString]);
    if ([[[eleResult stringValue] lowercaseString ] isEqualToString: @"successful"]){
        resultType = Successful;
    } else {
        resultType = InvalidUsernameOrPassword;
    }

    LoginResult *res = [[LoginResult alloc] init];
    res.result = resultType;

    for (CXMLElement *resultElement in [responseObj children] ) {
        NSLog([NSString stringWithFormat:@"%@ %@", [resultElement name], [resultElement stringValue]]);
    }

    //todo: fix enum parsing =[LoginResult loginResultTypeStringToEnum: [eleResult  stringValue]];  

    if(eleUser != nil) {
        CXMLElement *eleClientID = [eleUser nodeForXPath:@"ClientID" error:nil];
        CXMLElement *eleCompanyName = [eleUser nodeForXPath:@"CompanyName" error:nil];
        CXMLElement *eleCompanyContact = [eleUser nodeForXPath:@"CompanyContact" error:nil];
        CXMLElement *eleIsAgent = [eleUser nodeForXPath:@"IsAgent" error:nil];
        CXMLElement *eleParentID = [eleUser nodeForXPath:@"ParentID" error:nil];

        NSInteger *clientId = [[eleClientID stringValue] integerValue];
        NSString *companyName = [eleCompanyName stringValue];
        NSString *companyContact = [eleCompanyContact stringValue];
        bool isAgent = [Utils stringToBool:[eleIsAgent stringValue]];
        NSInteger *parentId = [[eleParentID stringValue] integerValue];
        User *user = [[User alloc] initWithData:clientId companyName:companyName companyContact:companyContact isAgent:isAgent parentId:parentId];
        res.user = user;
        // release elements

//      [eleClientID release];
//      [eleCompanyName release];
//      [eleCompanyContact release];
//      [eleIsAgent release];
//      [eleParentID release];

        //release raw values
//      [companyName release];
//      [companyContact release];
    }

//  [eleResult release];
//  [eleUser release];

    return res;
}

Part of me wants to say it's a bug with TouchXML, but I find that very unlikely. Is there any way to further track down the error?

EDIT: The definitions for the properties on the User class is:

@property (nonatomic, readwrite) NSInteger clientId;
@property (nonatomic, retain) NSString *companyName;
@property (nonatomic, retain) NSString *companyContact;
@property (nonatomic, readwrite) bool isAgent;
@property (nonatomic, readwrite) NSInteger parentId;

And the instance is initialized with:

-(User*)initWithData:(NSInteger *)clientId companyName:(NSString *)company companyContact:(NSString*)contact isAgent:(bool)agent parentId:(NSInteger*)parentId {
    //[self = super init];
    self.clientId= clientId;
    self.companyName= company;
    self.companyContact= contact;
    self.isAgent = agent;
    self.parentId = parentId;
    return self;
}

And the LoginResult class is:

@interface LoginResult : NSObject {
    LoginResultType result;
    User *user;

    NSString * const loginResultTypeArray[4];
}

@property (nonatomic, readwrite) LoginResultType result;
@property (nonatomic, retain) User *user;
Echilon
  • 10,064
  • 33
  • 131
  • 217

2 Answers2

0

Just a try: are you correctly retaining companyName and companyContatct in your User class?

EDIT:

Next thing I would check is loginResultTypeArray. How are string assigned to it? I guess that this advice will also sound trivial to you, but it is really difficult to come up with useful suggestion with so little code...

Can't you get some idea about which CFString is actually being released? If it is not an autoreleased object, possibly the stack trace could point at the method which is sending the release message... this would be very helpful...

Otherwise, I would try and NSLog some of your NSStrings addresses, so that you can compare them with the address you find in the error log (and, again, try and find out which string was actually reused after deallocation).

Finally, another approach to find out which string is used after deletion could be using method swizzling to replace NSString's dealloc with a method of yours that, before calling the swizzled dealloc, does some logging of the objec. This will produce much log info, but knowing the address of the string you could find easily what you need. Find here info about swizzling.

Community
  • 1
  • 1
sergio
  • 68,819
  • 11
  • 102
  • 123
0

This was a nightmare to track down. I had a method which returned an NSString *, which was then parsed by another method to produce an XML document, then release by the second method. I actually needed to autorelease it in the first method.

Echilon
  • 10,064
  • 33
  • 131
  • 217