Я работаю над приложением Iphone, которое использует базу данных SQLite в качестве основного источника данных модели.
Когда приложение открывается, одноэлементный объект «Модель» сканирует таблицу SQLite, использует каждую строку для создания объекта «Результат» (подкласс NSObject), а затем добавляет каждый результат в NSMutableArray.
Вот код для этого раздела, начиная сразу после того, как я нашел путь к базе данных:
- (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 numberWithFloat:(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");
}
Позже, один из моих контроллеров представления говорит моей Модели запустить повторяющийся NSTimer и вызывает метод для генерации случайного результата из 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];
}
И
-(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;
}
Вывод на консоль говорит мне, что в течение этого метода нормальное количество сохранений ... randomResult начинается с счетчика сохранения 0 после открывающего оператора if / then и счетчика сохранения 1 после того, как был возвращен.
Затем моя Модель применяет некоторые расчеты на основе других данных модели для генерации отформатированной строки результата для отображения в представлении:
-(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];
}
Моя проблема в том, что каждый раз, когда вызывается этот метод, и моя модель пытается получить значение floatValue свойства NSNumber *, я получаю сбой (используя точки останова, я выделил первую строку CalculateQuantity: как точка сбоя), и я получаю следующее сообщение в консоли:
- [CFNumber floatValue]: сообщение отправлено на освобожденный экземпляр 0x6332280
Это работает так: [sharedModel CalculateQuantity]; вызывается при первом тике таймера, а затем происходит сбой:
-(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];
}
Я не верю, что звоню дважды, и у меня все в порядке с памятью.
Самая запутанная часть заключается в том, что если я переместу первые две строки метода calculateQuantity в конец метода randomResult , я все равно получу сбой. Даже после того, как консоль просто сообщила мне, что счетчик сохранения равен 1, она сразу же сообщает, что я пытаюсь отправить сообщение в освобожденный экземпляр.
Я знаю, что это похоже на вопрос, который часто возникает, но я не смог выяснить проблему ни в одном из других потоков.