development

iOS 6/7에서 "재사용되는 테이블 셀에 대한 인덱스 경로 없음"메시지의 의미는 무엇입니까?

big-blog 2020. 12. 13. 10:11
반응형

iOS 6/7에서 "재사용되는 테이블 셀에 대한 인덱스 경로 없음"메시지의 의미는 무엇입니까?


iOS 6 (및 iOS 7 이후)으로 앱을 컴파일하기 시작한 이후로이 메시지가 표시되기 시작했습니다. UITableViews가 셀을 관리하는 방식이 iOS 6에서 다른 것을 알고 있지만 계속 작동하기 위해 코드를 수정할 필요가 없습니다. 그러나이 메시지가 아직 보지 못한 잠재적 인 문제를 가리킬 수 있다는 점이 우려됩니다. 누구든지 빛을 비출 수 있습니까?


iOS 7 GM / Release 빌드를 포함하여 iOS 7 베타 5부터 로그에이 오류가 나타나기 시작했지만, iOS 6 또는 이전 iOS 7 베타의 내 앱에서는이 오류가 발생하지 않았습니다. 많은 실험 끝에 원인을 찾았습니다.

UITableViewCell섹션 헤더보기에 개체를 사용 하고 tableView:viewForHeaderInSection:. 이것은 특히 iOS 5에서 Interface Builder를 사용하여 StoryBoard에서 프로토 타입 테이블 뷰 셀로 섹션 헤더 뷰를 쉽게 디자인 할 수있게 된 이후로 일반적인 관행으로 보입니다.

UIView섹션 헤더보기에 일반 서브 클래스 만 사용하도록 앱을 변경했을 때 오류가 사라지고 더 중요한 것은 내 테이블보기가 섹션 헤더를 임의로 삭제하는 것을 중단했습니다!

(iOS 7 베타 5부터) 뷰 계층 구조 UITableView의 모든 UITableViewCell개체와 해당 인덱스 경로 의 매핑을 내부적으로 유지하고 있는 것으로 보입니다. 섹션 머리글 (또는 바닥 글의 테이블보기 머리글)에는 인덱스 경로가 없기 때문에 UITableViewCell이러한보기에 개체를 사용 UITableViewCell하면 인덱스 경로가없는 a 찾을 때 테이블보기가 혼란스러워 집니다. , "재사용되는 테이블 셀에 대한 인덱스 경로 없음"오류가 발생하고 운이 좋지 않으면 테이블보기에 결함이 표시됩니다.

업데이트 : Apple Dev Forums에 대한 액세스 권한이 있다면 여기에 대한 스레드가 있습니다 (내가 시작한) : https://devforums.apple.com/message/882042#882042

해당 스레드에서 제안했듯이 리팩터링을 많이 원하지 않는 경우 UIView래퍼를 만들고 UITableViewCell섹션 헤더보기로 반환 할 수 있습니다 .

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
[view addSubview:cell];

return view;

그러나이 "래퍼" UIView접근 방식은 AutoLayout 및 장치 회전 UIView에서 잘 작동하지 않으므로 UITableViewCell답변의 주요 부분에 설명 된대로 하위 클래스가 아닌 머리글 및 바닥 글 셀에 대한 하위 클래스를 사용하는 것이 좋습니다 .


래퍼를 만드는 대신 UITableViewCell의 contentView를 반환 할 것입니다.

return cell.contentView;

나는 똑같은 문제가 있었고 문제를 찾는 데 몇 시간이 걸렸습니다. [textField becomeFirstResponder]셀을 설정 하는 동안 내가 호출 한 것으로 나타났습니다 (여기서 textField는 사용자 정의 tableviewcell의 일부였습니다). [textField becomeFirstResponder]차례 차례로 keyboardWillShow 알림을 게시하여 tableview가 너무 일찍로드되어 악명 높은 " no index path for table cell being reused "메시지가 발생합니다. 일단 해당 호출을 제거하면 문제가 사라졌습니다.


허용 된 답변 (mluisbrown)에 추가하여 헤더 셀에 autoresizingMask를 추가해야했습니다.

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[view addSubview:cell];
return view;

이것은 내부 UIKit 버그입니다. Apple의 자체 개발 포럼에서 언급했습니다. 어떤 버전이이 문제를 해결하는지에 대한 정보를 찾을 수 없었지만 최신 버전의 xcode에서 수정되었다고 가정합니다.


이전 게시물 (이것이 UIKit의 버그 인 것 같다고 언급 했음)에 추가로 특정 경우에 대한 해결 방법을 찾을 수있었습니다 (메시지가 테이블의 이상한 시각화 결함과 관련이 있음).

분명히 내 사용자 지정 셀이 재정의 -(void)setEditing:animated:되어 반환하는 데 너무 오래 걸렸습니다.

내 이전 코드는 다음과 같습니다.

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];
    [self someAdditionalCode];
}

다음과 같이 변경하여 수정할 수있었습니다.

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];

    // DRM: we want to perform the actions from this block in the main thread, but
    // asynchronously to avoid excessive delays which were causing issues.
    //
    dispatch_async(dispatch_get_main_queue(), ^void()
    {
        [self someAdditionalCode];
    });
}

resignfirstresponder 후 내 최종 업데이트를 수행하면 문제가 해결되었습니다 (사용자 지정 셀에 UITextFIeld가 있음).

-(void)textfieldEditDone
{
....

    [textField resignFirstResponder];
    [self.tableView endUpdates];

오류 메시지가 나타나는 것과 동일한 문제가 발생했습니다. 내가 볼 수있는 한 대리자 프로토콜의 일부로 텍스트 필드에서 호출하는 함수에서 테이블 뷰를 다시로드하여 발생합니다. 즉, textFieldDidEndEditing-> [controller.tableview 다시로드 ...]


기록을 위해 iOS 6에서 실행할 때도이 메시지가 발생했습니다. 상속되거나 가져온 일부 코드에 다음과 같은 내용이있는 것으로 보입니다.

(NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
    NSInteger rows = 0;
    if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) {
        rows = [delegate numberOfItemsInSection:section];

        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

beginUpdate : / endUpdate : 시퀀스가 ​​제거되면 문제가 마술처럼 사라졌습니다.


이것은 분명히 오래된 질문이지만 iOS8 +에서 여전히이 문제가 발생하는 모든 사람에게 도움이 될 수 있습니다.이 특정 오류 메시지에 대한 최상위 질문이기 때문입니다.

PINRemoteImage를 사용하여 사용자 지정 UITableViewCell 내부에있는 UIImageView에 이미지를 비동기 다운로드했습니다.

이미지가로드되면 행의 크기를 적절하게 조정하기 위해 (자동 레이아웃을 사용하는 동적 높이 셀) 다음을 호출했습니다.

self.tableView beginUpdates;
self.tableView endUpdates;

I was then getting the "no index path for table cell being reused" message and the app was crashing. I had thought the PINRemoteImageManagerResult block was on the main thread, however it turns out that it wasn't - therefore ensuring that the begin/end updates was called on the main thread fixed the issue.

dispatch_async(dispatch_get_main_queue(), ^(void){
                            [self.tableView beginUpdates];
                            [self.tableView endUpdates];
});

Well, I just used the better part of a day trying to figure this out, so hopefully this alternative explanation saves somebody else some time.

I had a tableview which was giving this message sometimes, when loading. It turned out to be caused by KVO notifications for Core Data objects firing while the view was loading. (On observing a change, my controller tried called reloadData on the tableview in question. Fixed by not observing the objects until the view had finished loading (previously I started observing the object once it was assigned via the accessor)

TLDR: Check to see if you might be trying to reload your data from something other than the main thread.


Maybe this helps someone: i once had this error while refreshing a single table view cell. I meant to do something like

NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2];
[self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow]
                           withRowAnimation:UITableViewRowAnimationFade];

But accidentally, i typed

NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2];

Notice the difference of the two indexpaths: one is created with indexPathForItem (wrong), the other with indexPathForRow (correct). This all resulted in very strange behaviour of the tableView and the error message in the headline.


It seems like my issue was triggered when I was trying to update the UI within a portion of the code that was a callback from a web call. I resolved by forcing UI updates to happen on the main thread. I used code like this.

void runOnMainQueueWithoutDeadlocking(void (^block)(void)){
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

I call it as follows inside of the success block of my background web call.

runOnMainQueueWithoutDeadlocking(^{
    [self.tableView beginUpdates];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
});

Yet another condition...

This happened when, not wanting a header, I returned nil.

Fix:

func tableView(tableView: UITableView,
               titleForHeaderInSection section: Int) -> String? {
    return ""
}

참고URL : https://stackoverflow.com/questions/12772197/what-is-the-meaning-of-the-no-index-path-for-table-cell-being-reused-message-i

반응형