Во-первых, небольшая ошибка ...
liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
Возможно, именно поэтому она вылетала, когда вы вызывали reload tableView.
Вы действительно хотите:
либо:
self.liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
(если вы настроили liveTimer как свойство, а не просто переменную-член)
или
[liveTimer release];
liveTimer = [[NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString] retain];
или
[liveTimer release];
liveTimer = [[NSString alloc] initWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
stringWithFormat:...
возвращает автоматически высвобождаемую строку, что означает, что она освобождается в конце текущего вращения в цикле выполнения.Это приведет к тому, что liveTimer будет указывать на неопределенную память по существу после завершения вашей функции.Использование self.liveTimer вместо liveTimer вызывает ваш метод синтезированного сеттера вместо того, чтобы просто устанавливать переменную напрямую, что заставляет ваш объект сохранять строку при ее установке (при условии, что вы настроили свойство live timer для сохранения, например, так: @property (nonatomic, retain) NSString *liveTimer;
Другие две альтернативы, перечисленные выше, освобождают старую версию строки, а затем сохраняют новую строку и устанавливают, а затем устанавливают переменную напрямую. Какой из вариантов вы предпочитаете между первым и последним, более или менее - дело вкусавторой - глупый (он создает строку, автоматически высвобождает ее, а затем снова сохраняет.)
Теперь к вашему вопросу.
В конце - (void)targetMethod: (NSTimer *)theTimer
вы захотите обновить текущую ячейку таблицы, если она существует. Предположим, что tableCell существует в строке 0 раздела 0:
-(void)targetMethod: (NSTimer *)theTimer {
// Everything you already had here, then...
NSIndexPath *cellIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *currentCell = [tableView cellForRowAtIndexPath:cellIndexPath];
// Returns the cell that's currently in the tableview at this location
currentCell.detailTextLabel.text = self.liveTimer;
}
Это должно сделать это ... если текущая ячейка не* не существует (потому что он прокручивается за пределы экрана) cellForRowAtIndexPath:
вернет ноль, а currentCell.detailTextLabel.text = self.liveTimer;
ничего не сделает (т.е. не ошибетсяили просто буквально ничего).
Редактировать:
Я только что заметил, что tableView не является одной из переменных вашего члена объекта ...
У вас есть UITableViewController
торчать, что вы можете получить?Если это так, просто используйте tableViewControllerVariableName.tableView
везде, где вы сейчас используете tableView.Является ли ваш RootViewController (в котором весь этот код) UITableViewController?Если это так, вызовите self.tableView
везде, где вы в данный момент вызываете tableView.Если нет, то где находится ваш tableView / tableViewController?Размещение вашего файла заголовка может помочь прояснить ситуацию ...
Редактировать 2:
Проблема с liveTimer и self.liveTimer связана с подсчетом удержания наobject.
liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
делает то, на что он похож - он устанавливает переменную liveTimer в новую строку.Принимая во внимание, что
self.liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
немного волшебно.Использование префикса self.
(или, в этом отношении anyObject.
) говорит компилятору «что я действительно хочу здесь сделать, это вызвать метод доступа для свойства liveTimer».Компилятор по существу заменяет вышеприведенную строку на:
[self setLiveTimer:[NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString]];
Поскольку у вас предположительно есть @synthesize liveTimer;
где-то в файле вашего класса, компилятор также автоматически создает для вас методы -(void)setLiveTimer:(NSTimer *)timer
и -(NSTimer *)liveTimer
.Они выглядят примерно так:
-(void)setLiveTimer:(NSTimer *)newLiveTimer
{
[liveTimer release]; // This is the old value. It may be nil, which is fine. Calling methods on nil objects in objective-c is just be a noop, not a crash.
liveTimer = [newLiveTimer retain];
}
-(NSTimer *)liveTimer
{
return liveTimer;
}
(Это немного упрощает, но это важно.)
Итак, когда вы вызываете self.liveTimer
, *Метод 1068 * вызывается вместе с объектом, старый объект, если таковой имеется, освобождается, а новый объект сохраняется.
[NSString stringWithFormat:...]
возвращает объект автоматического освобождения.Автоматически освобожденные объекты освобождаются после того, как управление возвращается из кода программы к предоставленному яблоком коду цикла выполнения.Они более или менее удобны, поэтому нам не нужно release
все маленькие объекты, которые мы используем один или два раза здесь и там.(Например, представьте, как утомительно было бы, если бы вам пришлось освобождать каждую созданную вами строку с синтаксисом @ "" ...)
Мы можем сказать, stringWithFormat:
возвращает автоматически освобожденный объект, потому что, по соглашению, методы, имена которых не начинаются с alloc
или copy
, всегда возвращают автоматически освобожденные объекты. Говорят, что такие методы «продают» объект. Мы можем использовать эти объекты в ближайшем будущем, но мы не «владеем» ими (т. Е. Мы не можем рассчитывать на то, что они будут там после того, как мы вернем контроль в систему.) Если мы хотим стать владельцем объекта продажи, мы должны вызвать [object retain]
для него, и тогда он будет там, пока мы явно не вызовем [object release]
или [object autorelease]
, и если мы не будем вызывать release
или autorelease
для него, прежде чем мы потеряем нашу ссылку на изменив переменную на что-то другое, мы ее утечем.
Контрастность с [[NSString alloc] initWithFormat:
. Этот метод «создает» объект. Мы владеем этим. Опять же, он будет там, пока мы явно не вызовем [object release]
.
Итак, вы устанавливали переменную-член liveTimer
для новой строки, но эта строка была автоматически освобождена, и как только ваш - (void)targetMethod: (NSTimer *)theTimer
вернулся, управление вернулось к коду цикла выполнения системы и этой строке был освобожден. Это означало, что liveTimer указывал на какое-то случайное место в памяти, которое когда-то содержало ваш строковый объект, но теперь содержало что-то еще - что-то неопределенное. Когда вы вызывали метод в этом случайном месте в памяти, он вылетал.
(Чтобы еще больше сбить с толку, [NSTimer scheduledTimerWithTimeInterval:target:selector:]
- это особый случай. Таймер сохраняет себя до тех пор, пока не сработает, поэтому эта часть вашего кода работает. Никто на самом деле не знает, почему NSTimer получает исключение; он чертовски запутан. оставшийся от дней NEXT - код, написанный в начале 90-х, когда он показался кому-то хорошей идеей.)
Итак, вы хотите использовать self.liveTimer
или self.timer
, или self.whatever
везде? Более менее. Обычно вы хотите сохранить новый объект и освободить старый. Единственное Одно из многих исключений состоит в том, что если вы «создаете» объект с [[Object alloc] init]
, этот объект приходит к вам с сохраненным счетчиком 1, в этом случае, используя синтаксис self.
сохранит объект во второй раз, что, вероятно, не то, что вы хотите. (Хотя, если вы установили self.liveTimer =
ранее и затем использовали liveTimer =
позже в своем коде, первая строка будет пропущена, потому что ничто никогда не освобождает ее. Это не всегда тривиально, решая, какой способ сделать это.)
Надеюсь, это немного прояснит ситуацию. Думаю, эта пунктирная система обозначений в target-c является наименее интуитивной частью языка. Обязательно прочитайте документ Apple по управлению памятью:
http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MemoryManagement.html