2017-03-23 2 views
0

나는 앱의 어려운 충돌을 추적하려고합니다.indexPath를 가져온 후 해당 indexPath에서 셀을 제거하기 전에 reloadData()를 호출하는 것이 안전하지 않습니까?

나는 효과적으로 수행 일부 코드가이 :

if let indexPath = self.tableView.indexPath(for: myTableViewCell) { 
    // .. update some state to show a different view in the cell .. 
    self.tableView.reloadData() 

    // show nice fade out of the cell 
    self.friendRequests.remove(at: indexPath.row) 
    self.tableView.deleteRows(at: [indexPath], with: .fade) 
} 

우려 reloadData()를 호출하면 어떻게 든 그 indexPath에서 셀을 삭제하려고 응용 프로그램 충돌, 그래서 난 그냥 잘못 검색 한 indexPath를 만드는 것입니다 . 그게 가능하니?

편집 :

  1. 사용자가 테이블 뷰 셀 <의 내부에 버튼을 추가 [친구] 탭 -
  2. 변경 버튼 여기 검색 indexPath :

    사용자 상호 작용이있다 [추가됨] 탭을 수신했음을 보여줍니다. < - 여기에서 reloadData가 호출됩니다.

  3. 짧은 지연 (0.5 초) 후에 셀이 사라집니다. < - 여기에서 # 1에서 indexPath로 호출 된 삭제

코드를 변경하여 reloadData를 호출하지 않고 대신 셀보기 만 업데이트 할 수 있습니다. 그게 낫지? 내가 그렇게하지 않으면 어떻게 될까?

+0

그냥이보고, 왜 당신은'reloadData()'에 대한 호출이 필요합니까? 이미 indexPath가 있으며 테이블보기에서 해당 셀을 제거하는 것처럼 보입니다. 'reloadData()'는 완전 재 구축을하기 때문에, 당신이 선택한 셀은 무효화 될 것입니다. – dstepan

+1

테이블을 다시로드 한 다음 행 삭제를 애니메이션으로 처리한다는 생각은 조금 궁금합니다. 테이블을 다시로드해야합니까 (즉, 'myTableViewCell'을 변경하는 셀 이외의 셀도 변경됩니까?)? 다른 셀이 변경되는 경우 원하는 것을 달성하는 더 좋은 방법이있을 수 있습니다 (예 : 행을 제거한 다음 셀을 제거하고 다른 특정 셀을 다시로드하는 방법). 또는 다른 셀이 변경되지 않으면'reloadData'를 잃어 버립니다. 실제로 무슨 일이 일어나고 있는지 설명하고 더 나은 조언을 할 수 있습니다. – Rob

+0

의견에 감사드립니다. 진행 상황을 자세히 설명하는 편집 섹션을 추가했습니다. –

답변

0

예, 아마도 테이블 뷰가 저장된 인덱스 경로를 무효화하는 것입니다.

문제가되는지 여부를 테스트하려면 reloadData()이 호출되기 직전에 표에 표시된 데이터를 변경하십시오.

문제가 발생하면 인덱스 경로 대신 테이블 셀이 나타내는 개체의 식별자를 사용해야합니다. 수정 된 코드는 다음과 같이 표시됩니다

func objectIdentifer(at: IndexPath) -> Identifier? { 
    ... 
} 

func indexPathForObject(_ identifier: Identifier) -> IndexPath? { 
    ... 
} 

if 
    let path = self.tableView.indexPath(for: myTableViewCell) 
    let identifier = objectIdentifier(at: path) { 

    ... 

    self.tableView.reloadData() 

    ... 

    if let newPath = indexPathForObject(identifier) { 
     self.friendRequests.removeObject(identifier) 
     self.tableView.deleteRows(at: [newPath], with: .fade) 
    } 
} 
1

개인적으로, 난 그냥이 아니라 전체 테이블보기보다, reloadRows(at:with:)와 함께 문제의 버튼을 다시 것입니다. 이 방법이 더 효율적 일뿐만 아니라 이미 목록의 상단으로 스크롤되지 않은 경우 목록 스크롤을 방해하지 않습니다.

그러면 약간의 시간이 걸려서 deleteRows(at:with:) 애니메이션이 연기됩니다. 나는 개인적으로 0.5 초가 너무 길다고 생각한다. 왜냐하면 사용자가 다른 행을 탭할 수 있고 애니메이션 중에 잘못된 시간에 탭하기에 불충분하다면 의도 한 것 이외의 행을 쉽게 얻을 수 있기 때문이다. 딜레이가 너무 길어서 그들이 무엇을 두드렸는지에 대해 긍정적 인 확인을 얻지 만 오랜 시간 동안 혼란스러운 UX를 산출하기는 어렵습니다. 어쨌든

, 당신은 같은 것을 끝낼 :. 내가 참조 형식을 사용했기 때문에

func didTapAddButton(in cell: FriendCell) { 
    guard let indexPath = tableView.indexPath(for: cell), friendsToAdd[indexPath.row].state == .notAdded else { 
     return 
    } 

    // change the button 

    friendsToAdd[indexPath.row].state = .added 
    tableView.reloadRows(at: [indexPath], with: .none) 

    // save reference to friend that you added 

    let addedFriend = friendsToAdd[indexPath.row] 

    // later, animate the removal of that row 

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { 
     if let row = self.friendsToAdd.index(where: { $0 === addedFriend }) { 
      self.friendsToAdd.remove(at: row) 
      self.tableView.deleteRows(at: [IndexPath(row: row, section: 0)], with: .fade) 
     } 
    } 
} 

(참고, 나는 ===를 사용 내가 다루는 경우 Equatable을 준수하는 값 유형 ==을 사용하십시오 그러나 이러한 것들은 당신의 큰 질문과 관련없는 구현 세부 사항입니다.) 수익률 그건

:

enter image description here

관련 문제