Message Sent To Deallocated Instance ... As far as I can tell, there's no reason it should be deallocated
I am working on an Iphone App that uses a SQLite database as its main source of Model data.
When the app opens, the singleton object called "Model" scans the SQLite table, uses each row to create a "Result" object (an NSObject subclass), and then adds each Result to an NSMutableArray.
Here's the code for that section, starting right after I have found the path for the database:
- (void)populateResultArrayWith:(NSString *)dbPath {
const char *sql = "SELECT * FROM results";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger pkInt = sqlite3_column_int(selectstmt, 0);
NSNumber *pk = [NSNumber numberWithInt:pkInt];
NSString *v = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
NSString *n = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
NSString *s = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)];
NSNumber *c = [NSNumber nu开发者_运维知识库mberWithFloat:(float)sqlite3_column_double(selectstmt, 4)];
NSString *t1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 5)];
NSString *t2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 6)];
NSString *t3 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 7)];
Result *resultObj = [[Result alloc] initWithPrimaryKey:(NSNumber *)pk
withVerb:(NSString *)v
withNoun:(NSString *)n
withSuffix:(NSString *)s
withCost:(NSNumber *)c
withTag1:(NSString *)t1
withTag2:(NSString *)t2
andTag3:(NSString *)t3];
[self.resultArray addObject:resultObj];
[resultObj release];
}
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
NSLog(@"Model: Closing Database");
}
Later, one of my view controllers tells my Model to start a repeating NSTimer, and triggers a method to generate a random result from the NSMutableArray:
-(void)startTimer
{
if (startDate && startDate != nil) {
startDate = nil;
}
self.modelCumulativeValueWasted = 0;
startDate = [[NSDate date] retain];
modelTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/1.0)
target:self
selector:@selector(tick)
userInfo:nil
repeats:YES];
[self randomResult];
}
And:
-(Result *)randomResult
{
if (randomResult != nil) {
randomResult=nil;
}
NSLog(@"Selected Result Retain Count At Beginning of Method = %i", [randomResult retainCount]);
// Generate a random int between 0 and the total count of the resultArray.
int randomIndex = arc4random() % [resultArray count];
// Select a result from the resultArray at that index - with an iVar.
randomResult = [resultArray objectAtIndex:randomIndex];
NSLog(@"Selected Result Retain Count At End of Method= %i", [randomResult retainCount]);
return randomResult;
}
The console read-out tells me that the retain count is normal during the course of this method... randomResult starts with a retain count of 0 after the opening if/then statement, and a retain count of 1 after it has been returned.
Then my Model applies some calculations based on other model data to generate a formatted Result string for display in the view:
-(void)calculateQuantity
{
// Get the float of the randomly selected result's "cost" property.
selectedCostFloat = [randomResult.cost floatValue];
// Calculate "how many of this result item could we buy" by dividing the cumulativeValueWasted by the costFloat.
float quantityFloat = (modelCumulativeValueWasted / selectedCostFloat);
NSLog(@"Quantity Float = %f", quantityFloat);
// Save this float as an NSNumber object, so a NSNumberFormatter can interpret it in ResultVC.
quantityNumber = [NSNumber numberWithFloat:quantityFloat];
}
My problem is that every time this method is called, and my model tries to get the floatValue of the NSNumber *cost property, I get a crash (using breakpoints, I isolated the first line of calculateQuantity: as the crash-point), and I get the following message in the console:
-[CFNumber floatValue]: message sent to deallocated instance 0x6332280
The way this works is that [sharedModel calculateQuantity]; is being called on the first tick of the timer, and then it crashes:
-(void)tick
{
// For "Time" every tick
NSDate *currentDate = [NSDate date];
NSTimeInterval countInSeconds = [currentDate timeIntervalSinceDate:startDate];
[df setDateFormat:@"HH:mm:ss"];
[df setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSDate *modelTimerDate = [NSDate dateWithTimeIntervalSinceReferenceDate:countInSeconds];
self.modelTimeString = [df stringFromDate:modelTimerDate];
NSLog(@"Time String: %@",self.modelTimeString);
//For "$" every tick
self.modelCumulativeValueWasted += self.modelMeetingValuePerSecond;
self.modelNumberToDisplayString = [NSString stringWithFormat:@"$%1.2f",self.modelCumulativeValueWasted];
NSLog(@"Cumulative Money Wasted: %@",self.modelNumberToDisplayString);
[self calculateQuantity];
}
I don't believe I am calling anything twice, and my memory management looks fine.
The most confusing part is that if I move the first couple lines of the calculateQuantity method to the end of the randomResult method, I still get the crash. Even after the console JUST told me that the retain count was 1, it immediately says I am trying to send a message to a deallocated instance.
I know this looks like a question that comes up a lot, but I haven't been able to figure out the problem from any of the other threads.
First, never rely on the -retainCount
since the system may do some magics on it.
Second, the randomResult
is return from resultArray
, so the randomResult
's owner is resultArray
, you don't know when the owner release its member. To own a object by yourself, you should send it a -retain
message, so change it to
-(Result *)randomResult
{
...
randomResult = [resultArray objectAtIndex:randomIndex];
return [[randomResult retain] autorelease];
}
Should be OK. Give it a try.
精彩评论