Я работаю над приложением для 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 * cost, я получаю сбой (используя точки останова, я изолировал первую строку 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, она сразу же сообщает, что я пытаюсь отправить сообщение освобожденному экземпляру.
Я знаю, что это похоже на вопрос, который возникает часто, но мне не удалось выяснить проблему ни в одном из других потоков.