Incredibly annoying/obscure NSAutoreleasePool error

Discussion in 'iOS Programming' started by floyde, Jul 12, 2009.

  1. floyde macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #1
    Hi guys, I'm losing my mind over this, I hope someone can help me.

    Basically I have this data source class that inherits from a Sqlite class that I created which has some generic select/insert methods. I call this data source class' insert method on the save button of my form. After this, the form closes and shows the previous one and obviously it releases my data source variable on the closing form. At this point the program crashes and floods the console with messages such as:

    Code:
    2009-07-12 13:50:56.589 CodenameChimp[776:bc03] *** _NSAutoreleaseNoPool(): Object 0x63d910 of class UIDeviceRGBColor autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0xc2d0 0xc3ec 0x91e82d70 0x939770c8)
    I do have the standard autorelease pool on my main file, so this makes absoultely no sense to me. Now, after a lot of commenting and un-commenting code, I've isolated the problem specifically to the insert method on the data source's sqlite superclass. If I don't call this method the data source class releases correctly. This is the code of the insert method:

    Code:
    - (NSNumber *)insertIntoDatabase:(const char *)sqlStatement withParameters:(NSArray *)params
    {
    	NSNumber *primaryKey = [NSNumber numberWithInt:-1];
    	sqlite3 *database;
    	
    	// Open the database from the users filessytem
    	if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
    	{
    		sqlite3_stmt *compiledStatement;
    		
    		if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
    		{
    			for (int i = 0; i < [params count]; i++)
    			{
    				NSString *paramValue = (NSString *)[params objectAtIndex:i];
    				sqlite3_bind_text(compiledStatement, i + 1, [paramValue UTF8String], -1, SQLITE_TRANSIENT);
    			}
    			
    			int success = sqlite3_step(compiledStatement);
    			
    			if (success != SQLITE_ERROR)
    				primaryKey = [NSNumber numberWithInt:sqlite3_last_insert_rowid(database)];
    		}
    		
    		// Release the compiled statement from memory
    		sqlite3_finalize(compiledStatement);
    	}
    	
    	sqlite3_close(database);	
    	return primaryKey;
    }
    Note that this code works and inserts rows correctly, although it can probably be improved since this is my first sqlite attempt on the iphone/objective c. I've checked all related code and everything I create is being released properly. I don't think I'm over-releasing either. If I don't call[dataSourceObject release]; the program works fine, but I think I should release it since I created it. So I guess that would cause leaks anyway.

    What am I doing wrong, any ideas? Thanks in advance.
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Few comments:

    Are there threads involved? This error usually is related to setting up a thread incorrectly.

    Do you have a breakpoint set on objc_exception_throw? If not then set one.

    What do you mean by 'the program crashes?' What is the crash? What is shown in the console besides the message that you showed? That message may be a red herring that's caused by the crash or runtime exception.

    You should look at FMDB. It's a set of wrapper classes for sqlite that works on the iPhone and is pretty good. Much better than writing your own.
     
  3. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #3
    Well the method is called on the button click. I don't know if that starts another thread.

    Haven't done that, I'll try it thanks.

    It freezes up. It's basically a dozen lines like the one I posted. There's no other error message:

    Code:
    [Session started at 2009-07-12 16:12:17 -0500.]
    2009-07-12 16:12:31.886 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x63ef30 of class UIDeviceRGBColor autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0xc33c 0xc458 0x91e82d70 0x939770c8)
    2009-07-12 16:12:31.920 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x638fd0 of class UIDeviceRGBColor autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0xc3d0 0xc458 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.016 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x63ff80 of class UIDeviceRGBColor autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0xc234 0xc480 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.162 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x645ae0 of class CABasicAnimation autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70c7c 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc53c 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.166 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x658260 of class NSCFNumber autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70d08 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc53c 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.202 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x647250 of class CABasicAnimation autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70c7c 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc56c 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.205 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x63cb20 of class NSCFNumber autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70d08 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc56c 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.207 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x63fc80 of class CABasicAnimation autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70c7c 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc598 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.211 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x6459a0 of class NSCFNumber autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70d08 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc598 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.214 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x63f980 of class CABasicAnimation autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70c7c 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc5c8 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.217 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x64dbe0 of class NSCFNumber autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70d08 0x31ddc194 0x31dd05b8 0x31e13534 0x31e13df8 0xc5c8 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.225 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x64bc50 of class CABasicAnimation autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x30a70c7c 0x31ddc194 0x31dd05b8 0x31dd4170 0x31dd3ed4 0x30a6b698 0xc798 0xc634 0x91e82d70 0x939770c8)
    2009-07-12 16:12:32.228 CodenameChimp[1053:bc03] *** _NSAutoreleaseNoPool(): Object 0x659940 of class NSConcreteValue autoreleased with no pool in place - just leaking
    Stack: (0x91f4fd74 0x91e7cdfc 0x91eef5ec 0x30a70d08 0x31ddc194 0x31dd05b8 0x31dd4170 0x31dd3ed4 0x30a6b698 0xc798 0xc634 0x91e82d70 0x939770c8)
    That's awesome. I was looking for something just like that. Perhaps if I use that code the error will go away.
     
  4. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #4
    Thanks PhoneyDeveloper, I migrated the code to FMDB and now it's working. I probably did something wrong in that insert method somewhere...
     
  5. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    You migrated your code in less than 2 hours? ¡Ay carumba!
     
  6. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #6
    Lol :p in this case migrated = "Changed my two select and one insert calls to work with FMDB". I had barely started working with sqlite, so there wasn't much to change.

    Anyway, it turns out that the _NSAutoreleaseNoPool messages had nothing whatsoever to do with my problem. These messages were caused by an animation that was running inside a thread. I just added an extra NSAutoreleasePool and now the leaks are gone.

    The actual error was related to what seems to be improper usage of NSMutableArray. I've fixed it but I still don't know why it's wrong. I hope you guys can enlighten me:

    Code:
    FMResultSet *rs = [database executeQuery:@"SELECT blah FROM SomeTable"];
    		
    		[mutableArray removeAllObjects];
    		
    		while ([rs next])
    		{
    			SomeObject *object = [[SomeObject alloc] init];
    			
    			//fill object with query values
    			
    			[mutableArray addObject:object];
    			[object release]; //taking out this line fixed the problem
    		}
    I fixed the problem by removing [object release];. I'm not sure I should be doing this, I thought I should release it since I created it. I hope I'm not fixing a problem by creating another...
     
  7. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #7
    Anyway, it turns out that the _NSAutoreleaseNoPool messages had nothing whatsoever to do with my problem. These messages were caused by an animation that was running inside a thread. I just added an extra NSAutoreleasePool and now the leaks are gone.

    That's what I said:

    Next:

    The code you show seems correct. If you alloc/init an object then you must release or autorelease it. Without it you will have a leak. There is probably something wrong with how you are creating the object, or setting its properties.

    What is the exact error that occurs?
     
  8. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #8
    Oops sorry, I had forgotten about that thread. You were right.

    I get a EXC_BAD_ACCESS. The object is just pretty much a couple of properties defined as "@property (nonatomic, retain)", and they're either NSNumbers or NSStrings. It doesn't even have an init method, so I just use alloc. To set its properties I'll just use something like "[NSNumber numberWithInt:[rs intForColumn:mad:"id"]]" or "[rs stringForColumn:mad:"name"]", for example.

    I create the object array with "[[NSMutableArray alloc] initWithCapacity:1]". Perhaps I should set a higher capacity, but I assumed that was dynamic. If I don't leave out the line I mentioned, I'll get the bad access message on "removeAllObjects". Not sure what's going on :confused:
     
  9. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #9
    Do you mean you use [[classname alloc] init] or something else? You always need both alloc/init, unless you're using a convenience constructor.

    If you're getting the bad access message when calling removeAllObjects then either the array itself is bad or one of the objects inside it is bad.

    If you set a breakpoint in the dealloc method of your class does it get called? Does the crash happen when releasing one of the ivars? Or does it crash inside [super dealloc]?
     
  10. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #10
    No :eek:, I just use [classname alloc]. The object I created inherits from NSObject, it has no methods, only a few properties. So I didn't think that I needed an init method. I guess I should call NSObject's init then...


    Thanks, I'll try this when I get home and I'll let you know.
     
  11. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #11
    You must always call init. The NSObject version of init does some required bookkeeping of the object. I'm sure that bad things will happen if you don't.

    Did you ever notice that there is no ivar in NSObject call retainCount? If I was implementing a retain count system I'd have an ivar in the object for this. Since it doesn't seem to be there it must be somewhere else with some kind of identifier for the object. That kind of stuff must be set up in init and torn down in dealloc.

    You showed this in your code

    Code:
    SomeObject *object = [[SomeObject alloc] init];
    but I guess you didn't really mean it.
     
  12. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #12
    Nope, I wrote that by memory, the actual code didn't call init :eek:. Hopefully this is what is causing the problem. I'll try changing it as soon as I get home.
     
  13. floyde thread starter macrumors 6502a

    floyde

    Joined:
    Apr 7, 2005
    Location:
    Monterrey, México
    #13
    Wow... you won't believe how stupid the mistake was...

    After doing this to create a TableViewCell from the database data:

    Code:
    SomeObject *someObject = (SomeObject *)[mutableArray objectAtIndex:indexPath.row];
    
    //create table cell from someObject's properties
    
    I called release on someObject... :eek: I was so focused on where it crashed that I missed that line. At least it's working now. Thanks for your help.
     

Share This Page