iPhone - didSelectRowAtIndexPath - 选择第26行或更大的神秘面纱

时间:2010-01-17 21:38:22

标签: iphone uitableview iphone-sdk-3.0

我的UITableView每个部分最多有50行,由plist字典填充,其中包含包含两个字符串(行标题/文件名和文件扩展名)的数组(行对象)的数组(部分)。

选择第1 - 25行(第0-24项),一切正常。但是选择大于26的行(第25项)并且应用程序崩溃。我是一个新手,我尝试研究答案,但我对如何研究这个问题感到茫然。表格每个部分只能有25行吗?

有什么想法吗?谢谢!

乔恩

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

    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
    NSMutableString *key = [categories objectAtIndex:section];
    NSMutableArray *sound = [categoriesSounds objectForKey:key];
    NSMutableString *soundName = [[sound objectAtIndex: row] objectAtIndex: 0];
    NSMutableString *soundOfType = [[sound objectAtIndex: row] objectAtIndex: 1];


    if (leftSwitch.on == YES) {
        showLeft.text = soundName;
        left    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
        AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                    fileURLWithPath:left], &soundNegZ); 
        AudioServicesPlaySystemSound (soundNegZ); 

        if (indexPath != leftOldIndexPath) {
            UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
            newCell.accessoryType = UITableViewCellAccessoryCheckmark;
            UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:leftOldIndexPath];
            oldCell.accessoryType = UITableViewCellAccessoryNone;
            leftOldIndexPath = indexPath;
        }
        [tableView deselectRowAtIndexPath:indexPath animated:YES];


    }

    if (downSwitch.on == YES) {
        showDown.text = soundName;
        down    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
        AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                    fileURLWithPath:down], &soundNegX); 
        AudioServicesPlaySystemSound (soundNegX);

        if (indexPath != downOldIndexPath) {
            UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
            newCell.accessoryType = UITableViewCellAccessoryCheckmark;
            UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:downOldIndexPath];
            oldCell.accessoryType = UITableViewCellAccessoryNone;
            downOldIndexPath = indexPath;
        }
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }

    if (rightSwitch.on == YES) {
        showRight.text = soundName;
        right    = [[NSBundle mainBundle] pathForResource:(@"%@", soundName) ofType:(@"%@", soundOfType)];
        AudioServicesCreateSystemSoundID((CFURLRef)[NSURL
                                                    fileURLWithPath:right], &soundPosX);    
        AudioServicesPlaySystemSound (soundPosX);

        if (indexPath != rightOldIndexPath) {
            UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
            newCell.accessoryType = UITableViewCellAccessoryCheckmark;
            UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:rightOldIndexPath];
            oldCell.accessoryType = UITableViewCellAccessoryNone;
            rightOldIndexPath = indexPath;
        }
        [tableView deselectRowAtIndexPath:indexPath animated:YES];

    }



}

对于控制台中的“EXC_BAD_ACCESS”,这是调试器输出(错误跟踪标有星号):

0x91a6cec0  <+0000>  mov    0x8(%esp),%ecx
0x91a6cec4  <+0004>  mov    0x4(%esp),%eax
0x91a6cec8  <+0008>  cmp    $0xfffeb010,%ecx
0x91a6cece  <+0014>  je     0x91a6cf35 <objc_msgSend+117>
0x91a6ced0  <+0016>  test   %eax,%eax
0x91a6ced2  <+0018>  je     0x91a6cf1a <objc_msgSend+90>
0x91a6ced4  <+0020>  mov    (%eax),%edx
0x91a6ced6  <+0022>  push   %edi
**0x91a6ced7  <+0023>  mov    0x20(%edx),%edi** 
0x91a6ceda  <+0026>  push   %esi
0x91a6cedb  <+0027>  mov    (%edi),%esi
0x91a6cedd  <+0029>  mov    %ecx,%edx
0x91a6cedf  <+0031>  shr    $0x2,%edx
0x91a6cee2  <+0034>  and    %esi,%edx
0x91a6cee4  <+0036>  mov    0x8(%edi,%edx,4),%eax
0x91a6cee8  <+0040>  test   %eax,%eax
0x91a6ceea  <+0042>  je     0x91a6cef5 <objc_msgSend+53>
0x91a6ceec  <+0044>  cmp    (%eax),%ecx
0x91a6ceee  <+0046>  je     0x91a6cf00 <objc_msgSend+64>
0x91a6cef0  <+0048>  add    $0x1,%edx
0x91a6cef3  <+0051>  jmp    0x91a6cee2 <objc_msgSend+34>
0x91a6cef5  <+0053>  pop    %esi
0x91a6cef6  <+0054>  pop    %edi
0x91a6cef7  <+0055>  mov    0x4(%esp),%eax
0x91a6cefb  <+0059>  mov    (%eax),%eax
0x91a6cefd  <+0061>  jmp    0x91a6cf09 <objc_msgSend+73>
0x91a6ceff  <+0063>  nop    
0x91a6cf00  <+0064>  mov    0x8(%eax),%eax
0x91a6cf03  <+0067>  pop    %esi
0x91a6cf04  <+0068>  pop    %edi
0x91a6cf05  <+0069>  xor    %edx,%edx
0x91a6cf07  <+0071>  jmp    *%eax
0x91a6cf09  <+0073>  sub    $0x4,%esp
0x91a6cf0c  <+0076>  push   %ecx
0x91a6cf0d  <+0077>  push   %eax
0x91a6cf0e  <+0078>  call   0x91a6d33f <_class_lookupMethodAndLoadCache>
0x91a6cf13  <+0083>  add    $0xc,%esp
0x91a6cf16  <+0086>  xor    %edx,%edx
0x91a6cf18  <+0088>  jmp    *%eax
0x91a6cf1a  <+0090>  call   0x91a6cf1f <objc_msgSend+95>
0x91a6cf1f  <+0095>  pop    %edx
0x91a6cf20  <+0096>  mov    0xe79d961(%edx),%eax
0x91a6cf26  <+0102>  test   %eax,%eax
0x91a6cf28  <+0104>  je     0x91a6cf30 <objc_msgSend+112>
0x91a6cf2a  <+0106>  mov    %eax,0x4(%esp)
0x91a6cf2e  <+0110>  jmp    0x91a6ced4 <objc_msgSend+20>
0x91a6cf30  <+0112>  mov    $0x0,%edx
0x91a6cf35  <+0117>  ret    
0x91a6cf36  <+0118>  nopw   %cs:0x0(%eax,%eax,1)

我的cellForRowAtIndexPath方法:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
    NSString *key = [categories objectAtIndex:section];
    NSArray *nameSection = [categoriesSounds objectForKey:key];
    static NSString *SectionsTableIdentifier = @"SectionsTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
                             SectionsTableIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc]
                 initWithStyle:UITableViewCellStyleDefault
                 reuseIdentifier:SectionsTableIdentifier] autorelease];
    }
    cell.textLabel.text = [[nameSection objectAtIndex:row] objectAtIndex: 0];

    if (leftSwitch.on == YES){
        NSUInteger leftRow = [leftOldIndexPath row];
        NSUInteger leftSection = [leftOldIndexPath section];
        cell.accessoryType = (row == leftRow && section == leftSection && leftOldIndexPath !=nil) ?
        UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
        }
    if (downSwitch.on == YES){
        NSUInteger downRow = [downOldIndexPath row];
        NSUInteger downSection = [downOldIndexPath section];
        cell.accessoryType = (row == downRow && section == downSection && downOldIndexPath !=nil) ?
        UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
    }
    if (rightSwitch.on == YES){
        NSUInteger rightRow = [rightOldIndexPath row];
        NSUInteger rightSection = [rightOldIndexPath section];
        cell.accessoryType = (row == rightRow && section == rightSection && rightOldIndexPath !=nil) ?
        UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
    }

    return cell;
}

5 个答案:

答案 0 :(得分:2)

通过分析您的代码,我可以看到一些您可能失败的地方。

首先:

NSMutableString *soundName = [[sound objectAtIndex: row] objectAtIndex: 0];
NSMutableString *soundOfType = [[sound objectAtIndex: row] objectAtIndex: 1];

声音数组中是否有超过25个元素?

其次:

if (indexPath != downOldIndexPath) {

什么是downOldIndexPath?你确定如果你把它传递给这个方法

UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:downOldIndexPath];

这是一条正确的索引路径吗?

答案 1 :(得分:0)

当您的应用程序崩溃时,您是否看到调试器控制台中记录的任何错误消息? (如果在调试应用程序时无法查看,请选择“运行”菜单 - &gt; XCode中的“控制台”菜单选项)。你应该在这里看到一些日志条目,这将有助于指明你正确的方向。

答案 2 :(得分:0)

我当前项目中有101行。据我所知,没有限制。

至于崩溃,你能告诉我们更多信息吗?像堆栈跟踪?控制台输出?

答案 3 :(得分:0)

如果您访问的元素多于所持有的数组,则会出现超出范围的异常 - 而不是EX_BAD_ACCESS崩溃。

这意味着您正在尝试访问已发布的内存。有两种可能性:

1)您从阵列中拉出的项目已被释放。这是不太可能的,因为你不得不做额外的发布以摆脱数组中的东西。

2)(最有可能)你已经发布了一个你试图从中获取数据的数组 - 或者更确切地说,你从某个地方获得数组然后忘记保留它(因为大多数事情都是通过其他方法提供给你的)是自动发布的。)

答案 4 :(得分:0)

我遇到同样的问题,我发现你已经通过以下方式解决了这个问题:

感谢Eddie,NSZombieEnabled指出了我正确的方向,我能够解决问题。原来我的索引路径保留计数需要在cellForRowAtIndexPath中增加1。 - Jonathan Cohen 1月25日18:00

对不起,我对iPhone编程有点新鲜,这究竟是什么意思?

我尝试了一些事情,但它们似乎都在工作我只是想知道哪种方法正确!?

我试过这个:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CheckMarkCellIdentifier = @"CheckMarkCellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CheckMarkCellIdentifier];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc]
                 initWithStyle:UITableViewCellStyleSubtitle
                 reuseIdentifier:CheckMarkCellIdentifier] autorelease];
    }

    // need to retain to stop this crashing with rows > ~26
    [indexPath retain];

    NSUInteger row = [indexPath row];
    NSUInteger oldRow = [lastIndexPath row];

    // Print the text
    cell.textLabel.text = [itemTextList objectAtIndex:row];

    // Print the detail text
    cell.detailTextLabel.text = [itemDetailTextList objectAtIndex:row];

    cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

    return cell;
}

另外(另外)我尝试了这两个:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger newRow = [indexPath row];
    NSUInteger oldRow = (lastIndexPath != nil) ? [lastIndexPath row] : -1;

    if (newRow != oldRow) {
        UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
        newCell.accessoryType = UITableViewCellAccessoryCheckmark;

        UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: lastIndexPath];
        oldCell.accessoryType = UITableViewCellAccessoryNone;

        // retain indexPath to use as last index path       
        lastIndexPath = [indexPath retain];
    }

    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger newRow = [indexPath row];
    NSUInteger oldRow = (lastIndexPath != nil) ? [lastIndexPath row] : -1;

    if (newRow != oldRow) {
        UITableViewCell *newCell = [tableView cellForRowAtIndexPath: indexPath];
        newCell.accessoryType = UITableViewCellAccessoryCheckmark;

        UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: lastIndexPath];
        oldCell.accessoryType = UITableViewCellAccessoryNone;

        // get a copy to use as last index path     
        lastIndexPath = [indexPath copy];
    }

    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

现在我正在向最后一个[indexPath copy]摇摆不定,这是从内存管理的角度来看这是正确的方法吗?或者我保留或复制它并不重要吗?

谢谢,