I just spent the last 3 hours trying to figure out this error. I would like someone to explain it to me so I don’t do it again.
I assigned an NSString instance variable without using “self”. When the class (“self”) released, I received a “bad access” error. I have done this exact same thing in another class with the same variable declarations and do not have this error. Below is my code. I commented out the line that broke and the line below fixes it. But I don’t understand why… Notice that there are other instance variables that do not cause this problem. Should I always use the “self” reserved word when assigning instance variables? Please let me know.
declarations
@property (nonatomic, readonly, assign) int IID;
@property (nonatomic, assign) int ProfileIID;
@property (nonatomic, retain) NSDate *NoteDate;
@property (nonatomic, copy) NSString *NoteText;
code snippet
// the default date format is Year-Month-Day
NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];
[df setDateFormat:kDateFormat];
IID = sqlite3_column_int(selectstmt, 0);
ProfileIID = sqlite3_column_int(selectstmt, 1);
// notice this does not cause a memory error
NoteDate = [[df dateFromString: [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)]] retain];
// the following may be NULL. Checking using the sqlite3_column_text method
const char *columnText = (const char *)sqlite3_column_text(selectstmt, 3);
if(columnText != NULL)
{
// this causes a memory error
//NoteText = [NSString stringWithUTF8String: columnText ];
// this does not cause memory error
self.NoteText = [NSString stringWithUTF8String: columnText ];
}
The reason that
is fine is because you retain the variable. Since you do not allocate the string, but call
stringWithUTF8StringonNSString, you do not take ownership of the variable, and so the string returned to you is autoreleased. However, since you retain it, this does not cause problems.If variables are returned autoreleased, then they are released when the autorelease pool is drained, which occurs at the end of each event (see more on autorelease pools). This is no good with an instance variable, because it needs to stick around after the current event.
When you assign the variable by:
Your setter method is not invoked, so the returned string (which, again, is autoreleased) is not retained, and so is released by the autorelease pool at the end of the event.
Calling it as:
does retain the string, since the line is another way of writing:
which invokes your setter method and retains the variable, preventing it from being released at the end of the current event.