2010-01-17 4 views
1

내 UITableView는 각 섹션에 최대 50 개의 행을 포함하고 plist 사전에 의해 채워지는 배열 (섹션)을 포함하는 배열 (행 개체) 파일 이름 및 파일 확장명).iPhone - didSelectRowAtIndexPath - 26 행 이상 선택

행 1 - 25 (항목 0-24)를 선택하면 모든 것이 정상적으로 작동합니다. 하지만 행 26 (항목 25)보다 큰 선택하고 응용 프로그램이 충돌합니다. 나는 이것에 초심자이고 나는 대답을위한 연구를 시도했다 그러나 나는 이것을 연구하는 방법에 대한 손실에있다. 테이블은 섹션 당 25 개의 행만 가질 수 있습니까?

아이디어가 있으십니까? 고맙습니다!

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 방법 :

- (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"를

, 이것은 (에러 트레이스 별표로 표시됨) 디버거 출력

- (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; 
} 
+0

cellForRowAtIndexPath 코드를 게시 할 수 있습니까? –

+0

감사합니다. –

답변

0

앱이 충돌하면 디버거 콘솔에 오류 메시지가 기록됩니까? (응용 프로그램을 디버깅하는 동안 볼 수없는 경우 Xcode에서 실행 메뉴 -> 콘솔 메뉴 옵션을 선택하십시오.) 올바른 방향으로 안내 할 수있는 몇 가지 로그 항목이 여기에 표시됩니다.

+0

안녕하세요 Eddie, 응답 시간을내어 주셔서 감사합니다. 디버거와 콘솔에 대해 알지 못했습니다 ... "EXC_BAD_ACCESS"메시지를 받았습니다.이 메시지는 매우 일반적이며 일반적으로 할당 된 메모리가 충분하지 않음을 의미합니다. . 위의 티켓에 콘솔 출력을 붙여 넣었으나 이제는 많은 스레드에 대한 출력이 있다는 것을 알아 두십시오. 추적 끝 부분에 따라 "int retVal = UIApplicationMain (argc, argv, nil, nil);"오류를 가리키는 것으로 보인다 " 다시 한번 감사드립니다. –

+0

문제 없습니다. http://www.tomwhitson.co.uk/blog/2009/04/debugging-with-nszombiesenabled/을 참조하십시오. EXC_BAD_ACCESS 오류를 추적 할 때 큰 도움이되는 NSZombieEnabled 환경 변수 설정에 대한 자세한 내용이 나와 있습니다. 해당 링크의 지침을 따르면 응용 프로그램이 더 이상 비정상적으로 죽지 않는다는 것을 알 수 있습니다. 그러나 원할 경우 콘솔에 "over-release"중인 객체를 알려주는 로그 메시지가 표시됩니다. 문제를 추적하여 해결 한 후에는이 환경 변수를 NO로 설정하는 것이 좋습니다. 즉, 순전히 디버깅 보조 도구입니다. –

+0

감사합니다. Eddie, NSZombieEnabled가 올바른 방향으로 나를 지적 했으므로 문제를 해결할 수있었습니다. cellForRowAtIndexPath에서 1 씩 증가시킬 필요가있는 인덱스 경로 보유 개수를 해제했습니다. –

0

현재 프로젝트에는 101 개의 행이 있습니다. 내가 아는 한도는 없습니다.

충돌과 관련하여 자세한 정보를 제공해 주시겠습니까? 스택 트레이스처럼? 콘솔 출력?

+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]; 

올바른 인덱스 경로인지 확인 하시겠습니까?

+0

안녕하세요, Adam - 감사합니다. 예, 일부 사운드 배열에는 표의 섹션에 따라 25 개가 넘는 요소가 있습니다. 요소 25 이하를 선택하면 모든 것이 예상대로 작동합니다. leftOldIndexPath, downOldIndexPath 및 rightOldIndexPath는 3 개의 해당 UISwitch (왼쪽, 오른쪽, 오른쪽) 중 하나가 ON으로 설정되어있는 동안 선택한 인덱스 경로를 유지하는 데 사용됩니다. 왼쪽 스위치가 켜져있는 동안 선택한 사운드의 체크 표시 액세서리 아이콘을 표시하고 아래 및 오른쪽 스위치가 켜져있는 동안 숨 깁니다. 확실히 올바른 색인 경로입니다. 행 <26 일 때 작동합니다. 다시 한번 감사드립니다. –

0

보유한 배열보다 많은 요소에 액세스하는 경우 EX_BAD_ACCESS 충돌이 아닌 범위를 벗어난 예외가 발생합니다.

즉, 출시 된 메모리에 액세스하려고합니다. 두 가지 가능성이 있습니다 :

1) 배열에서 꺼내는 항목이 해제되었습니다. 어레이에 보관 된 것을 없애기 위해 추가 릴리스를해야 했으므로 가능성은 거의 없습니다.

2) (아마도) 데이터를 가져 오려고하는 어레이 중 하나를 릴리스했거나 더 정확하게, 어딘가에서 어레이를 가져 와서 그것을 보관하는 것을 잊어 버렸습니다 (다른 어레이에서 제공 한 대부분의 것들 메소드가 자동으로 해제됩니다).NSZombieEnabled는 올바른 방향으로 절 지적하고 그 문제를 해결 할 수 있었다,

감사 에디 : 나는이 같은 문제에 봉착

+0

켄달 (Kendall)에게 감사드립니다. 메모리 관리에 대해 읽어 보겠습니다. –

0

, 난 당신이 다음에 의해 그것을 해결했습니다 참조하십시오. 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 복사], 이것이 메모리 관리 관점에서 올바른 방법입니까? 또는 내가 그것을 보유하거나 복사하는지 여부는 중요하지 않습니까?

감사합니다.

매트.

+1

self로 변경하여이 문제를 해결했습니다.lastIndexPath = indexPath; 이것은 보유자 등을 자동으로 (그리고 적절하게) 분류합니다. 초보자에게는 약간의 어려움이 있습니다! :-) –