Objective c 如何在NSTimer循环期间刷新TableView单元格数据

Objective c 如何在NSTimer循环期间刷新TableView单元格数据,objective-c,cocoa-touch,xcode,ios,Objective C,Cocoa Touch,Xcode,Ios,免责声明:我是一个新的iOS转换,所以请随时告诉我,我的整个方法是错误的。我只要求你们解释一下原因——我的目标是学习(当然,也是解决这个问题) 大家好,我是iOS编程新手,在尝试解决这个问题好几个小时后,我的无知和经验不足让我感觉很好。希望我能在这里找到帮助 我有一个简单的TableView应用程序,我正在为一个正在开发的更大的应用程序开发一个沙箱。我现在尝试实现的功能是在TableView单元格(即Cell.detailTextLabel.text)中对字幕文本进行伪实时更新 为了让您更好地

免责声明:我是一个新的iOS转换,所以请随时告诉我,我的整个方法是错误的。我只要求你们解释一下原因——我的目标是学习(当然,也是解决这个问题)

大家好,我是iOS编程新手,在尝试解决这个问题好几个小时后,我的无知和经验不足让我感觉很好。希望我能在这里找到帮助

我有一个简单的TableView应用程序,我正在为一个正在开发的更大的应用程序开发一个沙箱。我现在尝试实现的功能是在TableView单元格(即Cell.detailTextLabel.text)中对字幕文本进行伪实时更新

为了让您更好地了解目标:我正在尝试这样做,用户可以点击TableView单元格,一个“秒表”样式的计时器开始在字幕文本中计数

但我不知道如何更新cell.detailTextLabel.text A)从我的计时器方法内部(它说tableView未声明)和B)以重复刷新单元格,让用户看到“活动”计时器

所以,这里有一些代码(所有这些现在都在RootViewController中。最终我想为计时器之类的函数创建单独的类,但我只想先让它们工作起来)

我还应该补充一点,我现在在这个类中有很多全局(“接口?”)变量。这使得实验更容易,但如果这可能导致一些问题,请让我知道。我还在学习如何来回传递对象/变量等

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    self.runTimerFunctions;
}
然后是定时器功能(这些是接口变量):

数学和计算本身。结果生成格式为MM:SS.hh的单个字符串“liveTimer”,精确地向上“秒表”:

好的,liveTimer字符串是一个接口变量,所以我可以修改它并在整个过程中访问它(这可能不是实现这一点的方法,同样,我是一个noob,所以请在必要时纠正我)

在初始UITableViewCell创建位中,我使用liveTimer作为详细文本值,如下所示:

cell.textLabel.text = @"Name";
NSLog(@"liveTimer value is %@", liveTimer);
cell.detailTextLabel.text = liveTimer;
因此,从本质上讲,我现在拥有的东西,当用户按下列表项时,计时器开始在后台计数(我已经用NSLog确认它工作正常——如果我在targetMethod末尾提取liveTimer,它的格式正确,并且向上计数)

但我如何通过单元格文本的伪实时更新来反映这一点呢

当我将[tableView reloadData]放在任何我能放的地方时,它总是使程序崩溃(没有错误代码),但我不知道如何从targetMethod访问它(它告诉我在添加[tableView reloadData]时tableView未声明)

此外,[tableView reloadData]不断地使程序崩溃(没有错误消息),即使我试着通过实验将它放入,比如说,didSelectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    self.runTimerFunctions;

    [tableView reloadData];
基本上,我确信有一种简单的方法可以完成我想做的事情,但我对这门语言还太陌生,不知道如何去做。如果我试图在计时器循环中调用reloadData来重载系统,我不会感到惊讶。但话说回来,可能是其他原因

任何建议都将不胜感激。我正在尝试学习这里的语言,因此,尽管示例代码非常有用,但我同样对“学习如何钓鱼”感兴趣,因此我非常感谢解释为什么我所做的是错误的,以及更好的方法是什么,等等

提前感谢您的帮助;我期待参与论坛。

首先,一个小错误

liveTimer=[NSString stringWithFormat:@“%@:%@.%@”,分钟字符串、秒字符串、百分字符串];

这可能就是您调用reload tableView时它崩溃的原因

你实际上想要:

要么:

self.liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
(如果已将liveTimer配置为属性而不仅仅是成员变量)

stringWithFormat:…
返回一个自动释放的字符串,这意味着它在运行循环的当前旋转结束时被释放。这将导致liveTimer基本上在函数完成后指向未定义的内存。使用self.liveTimer而不是liveTimer会导致合成的setter方法失败调用,而不是直接设置变量,这会导致对象在设置字符串时保留字符串(假设已将live timer属性设置为保留,如:
@property(非原子,保留)NSString*liveTimer;
上面列出的另外两个选项都是先释放旧版本的字符串,然后保留新字符串,然后直接设置变量。第一个和最后一个选项中,您更喜欢哪一个或多或少是一个味道问题,第二个选项有点傻(它循环创建字符串,自动删除它,然后再次保留它。)

现在,谈谈你的问题

-(void)targetMethod:(NSTimer*)timer
的末尾,您需要实际更新当前表格单元格(如果存在)。假设表格单元格存在于第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:
将返回nil,而
currentCell.detailtextlab.text=self.liveTimer;
将不做任何事情(即没有错误,只是字面上什么都不做)

编辑:

我刚刚注意到tableView不是对象成员变量之一

你是否有一个
UITableViewController
可供使用?如果有,只要在当前使用tableView的任何地方使用
tableViewControllerVariableName.tableView
。就是你的RootViewController(所有这些代码都在其中)UITableViewController?如果是,请在当前调用tableView的任何位置调用
self.tableView
。如果不是,则在哪里分配tableView/tableViewController?可能会发布头文件
self.liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
[liveTimer release];
liveTimer = [[NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString] retain];
[liveTimer release];
liveTimer = [[NSString alloc] initWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
-(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;
}
liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
self.liveTimer = [NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString];
[self setLiveTimer:[NSString stringWithFormat:@"%@:%@.%@", minutesString, secondsString, hundredthsString]];
-(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;
}