Iphone 为什么这条线用水管冲洗我的桌面cell=[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
当我在cellForRowAtIndexPath:函数中注释掉这一行时:Iphone 为什么这条线用水管冲洗我的桌面cell=[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];,iphone,uitableview,delegates,Iphone,Uitableview,Delegates,当我在cellForRowAtIndexPath:函数中注释掉这一行时: cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; …然后所有的细胞每次都会再生,而不是重复使用。。。这会使我的所有tableview单元格当前值都得到完美设置。但是,我的单元格需要显示新旧值。当然,因为单元格总是被分配的,所以所有的历史值都会丢失 …当我将该行保留在那里
cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
…然后所有的细胞每次都会再生,而不是重复使用。。。这会使我的所有tableview单元格当前值都得到完美设置。但是,我的单元格需要显示新旧值。当然,因为单元格总是被分配的,所以所有的历史值都会丢失
…当我将该行保留在那里并滚动到tableview的底部时,表格底部单元格中的值将包含属于顶部单元格的一些值。。。我有点搞混了
简而言之,我有一个由自定义UITableViewCells组成的UITableView。自定义单元格具有以下功能:
Uisteper控件
用于存储调用的tableView的id委托,以便我可以在tableView中运行方法。
允许每个单元格在tableview中存储其节和行的属性
问题陈述:
当我加载tableview,用户点击单元格中的UIStepper控件时,它会调用委托函数doit:,返回tableview实现。在该函数中,自定义单元格的section和row属性工作正常,它们完美地指向数据源和tableView中的正确section和row,但是stepper.value以某种方式被设置为表中另一个单元格的stepper.value
而且,我只在表格中滚动显著距离时才真正注意到这种异常情况……例如。自上而下。底部单元格的stepper.value将是表格顶部附近单元格的stepper.value。所以我想我遇到了一个复杂的问题,源于细胞的缓存方式,等等
我包含了customCell类以及父表视图中的代码
有人看到我的错误吗?非常感谢
这是customTableViewCell头文件
回到实际的TableView,在那里我实例化了自定义单元格,我调用了自定义单元格的setDelegate:方法,如下所示,以便能够理解表中的哪个单元格被单击
该节目的主角是UIStepper控件,它允许用户上下移动屏幕
得分值,该值也显示在单元格上
#import <UIKit/UIKit.h>
@interface tvcCustomCellWithSetter : UITableViewCell {
id delegate;
NSNumber * row;
NSNumber * section;
int originalValueIsSet; }
@property (nonatomic, assign) IBOutlet UILabel *score; @property
(nonatomic, assign) IBOutlet UILabel *catAndWeight; @property
(nonatomic, assign) IBOutlet UILabel *orgValueText; @property
(nonatomic, assign) IBOutlet UILabel *orgValueValue; @property
(nonatomic, assign) IBOutlet UIStepper *theStepper; @property
(nonatomic, assign) id delegate; @property (nonatomic, assign)
NSNumber *row; @property (nonatomic, assign) NSNumber *section;
@property (nonatomic, assign) int originalValueIsSet;
- (IBAction) bumpTheScore;
- (id)delegate;
- (void)setDelegate:(id)newDelegate;
@end
这是包含customViewCell对象的TableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
tvcCustomCellWithSetter *cell = nil;
cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"customCell" owner:self options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[tvcCustomCellWithSetter class]]) {
cell = (tvcCustomCellWithSetter *)currentObject;
break;
}
}
}
// since the cell is a custom cell and it lives in a new class file, when events
// occur from toys in that cell (i.e. sliders, stepper, etc), the events go to that
// class file. I want those events to go to the simgrades class and run a reactive
// function in there. this is how you do that. see the two functions in the
// custom class that work with this line.
[cell setDelegate:self];
// similarly, save the current section and row into the custom cell itself
// so that later, when the stepper is clicked on one of the cells, we'll be able
// to know the location in the datasource that is being addressed by the user.
[cell setRow: [NSNumber numberWithInt: indexPath.row]];
[cell setSection: [NSNumber numberWithInt: indexPath.section]];
// Set up the cell...
[self.tableView setAllowsSelectionDuringEditing:NO];
SimCat *tmpCat = [simCatalog objectAtIndex: indexPath.section];
SimGrade *tmpGrd = [[tmpCat simGrades] objectAtIndex:indexPath.row];
float averageScore, _score, _total;
_score = [tmpGrd.scoreValue floatValue];
_total = [tmpGrd.scorePossible floatValue];
averageScore = (_score / _total) * 100;
// Configure the cell... Category name and description
if (tmpGrd.isSimGrade) {
cell.score.text = [NSString stringWithFormat:@"SimGrade: %2.2f%% - (%@ of %@)", averageScore, [tmpGrd.scoreValue stringValue] , [tmpGrd.scorePossible stringValue]];
//for simulation grades, null out the orgValue labels.
cell.orgValueValue.text = [NSString stringWithString: @""];
cell.orgValueText.text = [NSString stringWithString: @""];
} else {
cell.score.text = [NSString stringWithFormat:@"Actual: %2.2f%% - (%@ of %@)", averageScore, [tmpGrd.scoreValue stringValue] , [tmpGrd.scorePossible stringValue]];
//set the orig value label and turn on the boolean that shows that you've set this already.
if (! cell.originalValueIsSet ) {
cell.orgValueValue.text = [NSString stringWithFormat:@"%@", [tmpGrd.scoreValue stringValue]];
cell.orgValueText.text = [NSString stringWithString: @"Original Value:"];
cell.originalValueIsSet = true;
}
}
cell.catAndWeight.text = [NSString stringWithFormat:@"Category: %@, Wt: %d", tmpCat.catName, [[tmpCat catWeight] intValue]];
[cell.theStepper setValue:[tmpGrd.scoreValue floatValue]];
[cell.theStepper setMaximumValue:[tmpGrd.scorePossible floatValue]];
[cell.theStepper setMinimumValue:0];
return cell;
}
这就是我的问题所在。请参阅下面代码中的问题描述
- (void) doit: (id) sender {
NSLog(@"it worked - i got back inside the tableview that houses the custom cells");
NSLog(@"the user touched the UISetter control on a cell in section: %d", [[(tvcCustomCellWithSetter *)sender section] intValue]);
NSLog(@"and that cell was in row: %d of that section", [[(tvcCustomCellWithSetter *)sender row] intValue]);
// find the right section and row in the tableview's data source
// point to the section indicated by the "section" passed in from the custom cell.
SimCat *cat = [simCatalog objectAtIndex:[[(tvcCustomCellWithSetter *)sender section] intValue] ];
// now point at the array item that corresponds to the "row" passed in from the custom cell
SimGrade *grade = [[cat simGrades] objectAtIndex:[[(tvcCustomCellWithSetter *)sender row] intValue]];
// now that we are pointing at the right array item in the tableview's datasource, update it's value to that of the UIStepper
// control's value.
// THE PROBLEM OCCURS IN THE FOLLOWING LINES. The before value that is printed out is perfect. So I know I am able to
// reference the correct value in the datasource that the user has just incremented or decremented with the UIStepper
// control. The "theStepper.value" should contain a number that is one more or one less than the previous value...
// HOWEVER, the value stored in theStepper.value is actually a value from one of the other cells in the table.
// I'm thinking that this has to do with the way the table cells are cached. I usually see this error when I scroll to the
// bottom of the tableview.
NSLog(@"before: %f", [[grade scoreValue] floatValue]);
grade.scoreValue = [NSNumber numberWithFloat: [[(tvcCustomCellWithSetter *)sender theStepper] value]];
NSLog(@"after: %f", [[grade scoreValue] floatValue]);
// you have changed some values in the Tableview's datasource so you should repaint the view.
[self loadHTMLHeader];
[[self tableView] reloadData];
return;
}
为了防止步进值传递,如果您的dequeueReusableCell。。方法返回一个单元格
因此:
一旦您这样做了,您就可以进行进一步的调试,看看您的值是否设置得不正确。如果值为零,那么它应该是零。否则,您就知道它无法为特定的单元格设置正确的值,然后在代码中放置断点并查看变量值等
编辑:我会更具体一些。从调试中,您将在逐步完成代码时看到:
在设置正确的值之前,将步进器值显式设置为默认值,或
这些值没有显式设置为默认值,这意味着您的值重置代码不起作用。
然后:
步进器值设置为当前单元格的正确值,或
步进器值设置为与预期值不同的值,在这种情况下,您需要在设置该值的点跟踪代码,并查看索引是什么以及它最终拾取的值,等等,或者
步进器值与其默认值完全没有改变,这意味着要设置的代码正在崩溃,或者出现了一种不寻常的情况,即您最终得到一个nil、0或根本没有执行代码来设置值,您需要跟踪并查看代码到达该阶段的位置。
这应该是您的标准调试过程。我最终解决了这一问题,方法是将我的头撞到墙上,并对UIStepper类进行子类化,以便添加一个row和section属性,使我能够确定单击控件时显示控件的是哪个tableview单元格。我还使用了一个setTarget方法,在cellforrowatindexpath方法期间放置在每个单元格上,每当UIStepper上的值发生更改时,它都会调用tableview类中的函数。在这个函数中,我能够利用customStepper中的行和节值来精确定位表中的行,从而确定需要更新的数据源
唷。您将所有属性标记为assign-@property非原子,assign ibuiLabel*score;。更正确的方法是将其标记为保留。谢谢,铍。但我把所有的都改成了“保留”,没有快乐。下面是问题陈述的更新。当我在TableView中注释掉下面的行时,单元格不会被重用,UIStepper.value是正确的。但这破坏了我保持细胞原始分数值的能力,因为每个细胞每次都会再生。我
在单元格中显示新旧值。这是我上面提到的行:cell=tvcCustomCellWithSetter*[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];谢谢,darvidsOn,我会设置它并尝试一些断点调试。回到你身边:20米。不,没有欢乐。我真的被这件事难住了。还有其他建议吗?
- (void) doit: (id) sender {
NSLog(@"it worked - i got back inside the tableview that houses the custom cells");
NSLog(@"the user touched the UISetter control on a cell in section: %d", [[(tvcCustomCellWithSetter *)sender section] intValue]);
NSLog(@"and that cell was in row: %d of that section", [[(tvcCustomCellWithSetter *)sender row] intValue]);
// find the right section and row in the tableview's data source
// point to the section indicated by the "section" passed in from the custom cell.
SimCat *cat = [simCatalog objectAtIndex:[[(tvcCustomCellWithSetter *)sender section] intValue] ];
// now point at the array item that corresponds to the "row" passed in from the custom cell
SimGrade *grade = [[cat simGrades] objectAtIndex:[[(tvcCustomCellWithSetter *)sender row] intValue]];
// now that we are pointing at the right array item in the tableview's datasource, update it's value to that of the UIStepper
// control's value.
// THE PROBLEM OCCURS IN THE FOLLOWING LINES. The before value that is printed out is perfect. So I know I am able to
// reference the correct value in the datasource that the user has just incremented or decremented with the UIStepper
// control. The "theStepper.value" should contain a number that is one more or one less than the previous value...
// HOWEVER, the value stored in theStepper.value is actually a value from one of the other cells in the table.
// I'm thinking that this has to do with the way the table cells are cached. I usually see this error when I scroll to the
// bottom of the tableview.
NSLog(@"before: %f", [[grade scoreValue] floatValue]);
grade.scoreValue = [NSNumber numberWithFloat: [[(tvcCustomCellWithSetter *)sender theStepper] value]];
NSLog(@"after: %f", [[grade scoreValue] floatValue]);
// you have changed some values in the Tableview's datasource so you should repaint the view.
[self loadHTMLHeader];
[[self tableView] reloadData];
return;
}
cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"customCell" owner:self options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[tvcCustomCellWithSetter class]]) {
cell = (tvcCustomCellWithSetter *)currentObject;
break;
}
}
} else {
cell.theStepper.value = 0;
cell.theStepper.maximumValue = 1;
// cell.theStepper.minimumValue = 0; this should already be set properly
}