
개념 정리
UITableView는beginUpdates와endUpdates라는 메소드를 가지고 있다. 이 메소드들은 테이블 뷰에서 애니메이션과 함께 여러 변경 사항을 한꺼번에 업데이트 할 수 있는 방법을 제공한다.
beginUpdates와 endUpdates는 테이블뷰에서 일어나는 이벤트(셀 삽입, 삭제, 변경 등)를 애니메이션으로 묶어서 처리할 수 있다.
사용 방법은 무척 간단한데, beginUpdates와 endUpdates 코드를 작성하고, 그 사이에 셀 삽입, 삭제 등과 같은 테이블뷰 변경 작업을 진행하는 코드를 작성하면 된다.
// 메소드 사용 예시
tableView.beginUpdates()
// 삽입, 삭제, 또는 업데이트 메소드 호출
tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
tableView.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
tableView.reloadRows(at: [IndexPath(row: 2, section: 0)], with: .automatic)
tableView.endUpdates()
beginUpdates와 endUpdates 코드를 사용하면 테이블 뷰에서 여러개의 업데이트가 있을 때, 각 작업마다 테이블 뷰를 새로 고치는 대신 한 번에 묶어서 처리할 수 있기 때문에 성능 면에서 더욱 효율적으로 코드를 작성할 수 있다.
또, beginUpdates와 endUpdates 코드를 사용하면 업데이트 중에 테이블 뷰의 데이터 소스와 UI 상태를 동기화 하도록 강제하기 때문에 UI의 일관성을 유지할 수 있다는 장점이 있다.
다만, beginUpdates 호출 전과 endUpdates 호출 후에 데이터 소스는 일관성을 가져야 한다.
func addItem() {
// 데이터 소스 업데이트
items.append("새로운 항목")
// 테이블 뷰 업데이트
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: items.count - 1, section: 0)], with: .automatic)
tableView.endUpdates()
}
func removeItem(at index: Int) {
// 데이터 소스 업데이트
items.remove(at: index)
// 테이블 뷰 업데이트
tableView.beginUpdates()
tableView.deleteRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
tableView.endUpdates()
}
func updateItem(at index: Int, with newValue: String) {
// 데이터 소스 업데이트
items[index] = newValue
// 테이블 뷰 업데이트
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
tableView.endUpdates()
}
beginUpdates와 endUpdates를 사용하는 이점beginUpdates와 endUpdates가 정말 좋긴 하지만, 사용할 때 주의해야 할 점이 몇 가지 있다.
IndexPath가 데이ㅓㅌ 소스 배열의 인덱스와 일치해야 한다.beginUpdates와 endUpdates는 중첩해서 호출할 수 없다.지금까지 나는 테이블뷰를 업데이트 할 때 reloadData()나 reloadRows(at:with:)를 주로 사용해왔다. 이 두 메소드 역시 테이블뷰의 UI를 업데이트 하는 역할인데 어떤 점이 다를까?
지금부터 살짝 알아보도록 하자
1️⃣ reloadData
reloadData는 테이블 뷰 전체를 다시 로드하는 기능이다. 데이터 소스의 변경 사항을 반영하여 모든 섹션과 모든 셀을 다시 생성한다.
// 사용 방법 예시
tableView.reloadData()
이 방법을 사용하면 한 번의 호출로 간단하게 테이블뷰의 UI를 업데이트 할 수 있기 때문에 편리하고, 전체 데이터 소스가 변경될 경우 유용하게 사용할 수 있다.
다만, reloadData는 효율성이 저하되는 단점이 있다. 전체 테이블 뷰를 다시 그리기 때문에 변경된 셀 뿐만 아니라 변경된 점이 없는 셀도 다시 로드하기 때문에 그렇다.
또, 셀 추가나 삭제, 변경 등의 작업을 수행하여도 애니메이션이 제공되지 않기 때문에 부드러운 UI의 변경을 원한다면 부적합하다.
(UIView.animate()메소드를 쓸 수도 있지만 번거롭다.)
게다가 만약 테이블 뷰의 데이터가 많을 경우 불필요한 UI 업데이트로 인해 성능이 저하될 수 있으므로 적절히 상요해야 한다.
2️⃣ reloadRows
reloadRows는 특정 셀만 다시 로드하는 기능이다. 주로 데이터 소스가 일부만 변경되는 경우 사용한다.
// 사용 예시
tableView.reloadRows(at: [indexPath], with: .automatic)
이 방법을 사용하면 필요한 셀만 업데이트하기 때문에 성능 면에서 볼 때 더욱 효율적이다. 또, 기본적으로 애니메이션을 지원하기 때문에 UI 업데이트를 더 부드럽게 구현할 수 있다.
주의할 점은 reloadRows를 쓸 때는 데이터 소스의 상태가 테이블 뷰와 정확히 동기화 되어야 한다. 만약 동기화가 잘못되면 코드가 충돌하거나 비정상적인 동작이 발생할 수 있기 때문에 데이터 소스와의 동기화가 중요하다.
3️⃣ Updates
beginUpdates와 endUpdates는 위에서도 설명한 것처럼 여러 변경 사항(셀 삽입, 삭제, 변경 등)을 애니메이션과 함께 그룹화하여 처리하는 기능이다.
// 사용 예시
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: 2, section: 0)], with: .automatic)
tableView.deleteRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
tableView.endUpdates()
이 코드는 애니메이션을 지원하기 때문에 삽입, 삭제, 갱신 등의 작업이 자연스럽게 처리되고, 여러 작업을 한 번에 묶어서 처리할 수 있어서 코드를 더욱 간결하고 구조적으로 작성할 수 있게 된다.
또, 모든 데이터를 업데이트 하는 것이 아니라 필요한 부분만 업데이트 하며, 애니메이션을 자동으로 최적화 해주기 때문에 편리하다.
그러나 beginUpdates와 endUpdates를 사용하면 코드가 다소 복잡해질 수 있으며, 데이터 소스와의 일관성을 신경 써야 하기 때문에 불편할 수 있다.
또, 업데이트 작업이 많거나 잘못 설정되면 성능에 부정적인 영향을 미칠 수 있기 때문에 비효율적인 사용을 하지 않도록 주의해야 한다.
4️⃣ 비교 요약
| 방법 | 업데이트 범위 | 애니메이션 | 성능 효율성 | 사용 시기 |
|---|---|---|---|---|
| reloadData | 전체 테이블 뷰 | 없음 | 낮음 | 데이터 전체를 새로 고쳐야 할 때, 섹션/셀 변경이 많을 때 |
| reloadRows | 특정 셀 | 있음 | 중간~높음 | 일부 데이터만 변경할 때, 데이터 소스가 정확히 동기화된 경우 |
| beginUpdates/endUpdates | 여러 작업(삽입, 삭제, 변경) | 있음 | 높음 | 여러 변경 작업을 그룹화하여 애니메이션과 함께 처리할 때 |
// 전체 데이터 소스 변경 시
dataArray = ["Item 1", "Item 2", "Item 3"]
tableView.reloadData()
// 데이터 소스의 특정 항목 변경 시
dataArray[0] = "Updated Item"
tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
// 삽입, 삭제, 갱신 작업을 함께 처리
dataArray.append("New Item")
dataArray.remove(at: 1)
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: 3, section: 0)], with: .automatic)
tableView.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
tableView.endUpdates()
각각의 방법은 상황에 따라 알맞게 사용하는 것이 가장 좋으며, 무엇이 뛰어나다고 말할 수 없다.
데이터 변경 크기에 따라 선택하거나, 애니메이션의 여부가 중요하거나, 성능이 중요하거나, 각자 필요한 상황에 적절히 사용하면 된다.
오늘은 개인과제를 수행하며 테이블 뷰에 대해 여러가지 알게된 사실 중 하나인
beginUpdates와 endUpdates에 대해 정리해 보았다.
오늘 공부한 내용을 바탕으로 앞으로는 더욱 효율적인 코드를 작성할 수 있도록 노력해 보려고 한다.
항상 잘 구경?하고 갑니다..ㅎㅎ