大器晩成
TableViewController - 셀의 갱신과 삭제 본문
테이블뷰 컨트롤러에서 자주 사용되는 갱신과 삭제에 대해서 정리해보려고 합니다.
아래 설명하는 방법을 제외하고도 여러 가지가 있겠지만, 우선적으로 자주 사용하는 것들을 기준으로 정리해 보도록 하겠습니다.
갱신
우선 갱신에는 크게 두 가지 방법이 있습니다.
1. 전체를 갱신하는 tableView.reloadData ()
2. 특정 셀의 데이터를 다시 로드하는 tableView.reloadRows(at: [IndexPath], with: UITableView.RowAnimation)
전체코드는 아래에서 확인하면 됩니다. 우선 스와이프 기준으로 각각의 기능이 어떻게 실행되는지 확인해 보고 왜 이런 결과가 나오지는 생각해 봅시다.
왼쪽과 오른쪽 스와이프에서 사용된 코드는 아래 코드를 참고해 주길 바라며,
우선 동작 간의 어떤 차이가 있는지 알아보면 다음과 같습니다.
reloadData()를 할 경우 header의 값을 바꿔 header도 변경했지만,
reloadRows()에서는 헤드의 값은 변경되지 않고 빈 헤더로만 나왔습니다.
이는 두 함수의 동작에 차이에서 알 수 있는데, 우선 셀을 만들 때 사용되는 필수 함수 numberOfRowsInSection(), cellForRowAt()는 reloadData() 함수를 사용할 경우 무조건 출력이 됩니다.
이후 reloadData() 함수는 다른 overried 된 함수들을 모두 호출하기 때문에 헤더도 수정이 될 수 있습니다. (리스트의 값의 변경도 가능)
하지만, reloadRows()를 호출할 경우 cellForRowAt 함수만 호출되기 때문에 셀 안에 값의 변경은 가능하지만, 실제 데이터를 삽입, 삭제할 수는 없습니다. 이는 reloadRows함수가 numberOfRowsInSection을 재호출 하지 않기 때문입니다. 리스트를 강제 삭제하는 방법도 있지만, 결과적으로 numberOfRowsInSection 호출하지 않으면 리스트의 크기와 섹션의 적용된 크기가 다르기 때문에 오류가 발생합니다.
전체 갱신이 필요할 때는 reloadData(), 특정 셀을 갱신하고 싶을 때는 reloadRows() 함수를 호출하는 것이 속도에서 조금 더 빠를 수 있습니다.
뇌피셜) reloadRows() 함수에서 titleForHeaderInSection() 함수가 호출되지 않는데, 왜 헤더의 값은 고정이 아니고, 빈 문자열로 나올까 하는 의문을 가질 수 있는데, 이는 아마도 스위프트에서 titleForHeaderInSection() 내부에서는 다른 방식으로 헤더를 참조하고 있을 수도 있다고 생각합니다. 그래서 header라는 변수를 리턴했지만, 중간에 변수의 값을 변경함으로써 뭔가 header의 기존값이 강제로 바뀌었기 때문에, tableview에서는 인식을 못해서 nill 또는 ""으로 처리가 되지 않았을까 싶습니다.
특정 셀 삭제
셀 삭제에는 해당 함수를 사용할 수 있습니다. tableView.deleteRows(at: [indexPath], with: .fade), with은 애니메이션이기 때문에 우선 해당 내용에서는 생략하겠습니다.
위에 예제와 같이 오른쪽 스와이프는 전체 갱신이며, 오른쪽은 특정 셀만 삭제합니다.
보이는 것과 같이 특정 셀만 삭제할 때도 reloadData()처럼 numberOfRowsInSection(), cellForRowAt()는 호출되지만, titleForHeaderInSection()는 호출되지 않기 때문에 헤더는 바뀌지 않습니다.
reloadRows()는 왜 numberOfRowsInSection()은 호출하지 않을까라고 생각해 보면 단순합니다. reloadRows는 그냥 해당 셀을 갱신하기 때문에 해당 셀이 삭제 또는 추가되는 것에 대한 생각을 안 합니다. 하지만 deleteRows()는 함수명에도 삭제하고 적혀있기 때문에, 삭제될 것을 애플에서는 이미 알고 있기 때문에 내부적으로 최소 numberOfRowsInSection(), cellForRowAt() 이 두 개의 함수는 호출해야 한다라고 구조화가 되어있을 것으로 생각됩니다.
이것도 마찬가지로 특정 행을 삭제하고 싶을 때는 reloadData() 보다는 deleteRows() 함수가 속도적인 측면에서 빠를 수 있습니다.
추가적으로 리스트를 먼저 deleteRows()를 사용할 때에는 리스트를 먼저 지우고 테이블 뷰를 지워야 합니다. 테이블 뷰는 IndexPath를 기준으로 지우기 때문에, 먼저 테이블뷰를 지울 경우 list에는 아직 남아있기 때문에 numberOfRowsInSection(), cellForRowAt()에서 list의 개수가 맞지 않는 오류가 발생합니다.
전체코드
import UIKit
class qqTableViewController: UITableViewController {
var str: [String] = ["1","2","3","4"]
var header = "Hello"
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return str.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "youngcell")!
cell.textLabel?.text = str[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let test = UIContextualAction(style: .normal, title: "전체갱신") { (_, _, complete: @escaping (Bool) -> Void) in
self.str.remove(at: indexPath.row)
tableView.reloadData()
complete(true)
}
header = "오른쪽 스와이프 동작"
return UISwipeActionsConfiguration(actions:[test])
}
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let test = UIContextualAction(style: .normal, title: "삭제") { (_, _, complete: @escaping (Bool) -> Void) in
self.str.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
// self.str[indexPath.row] = "업데이트 되었습니다"
// tableView.reloadRows(at: [indexPath], with: .automatic)
complete(true)
}
header = "왼쪽 스와이프 동작"
return UISwipeActionsConfiguration(actions:[test])
}
// 섹션의 Header (옵션)
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return header
}
}
reloadData() | deleteRows(at:with:) |
테이블의 데이터가 완전히 변경되거나 전체를 다시 그려야 할 때 | 데이터를 부분적으로 수정(삽입, 삭제, 이동)할 때 |
간단한 UI 갱신이 필요하고 애니메이션이 중요하지 않을 때 | 애니메이션 효과를 적용하고 싶을 때 |
'iOS > UiKit' 카테고리의 다른 글
TableViewController - prepareForReuse() (0) | 2025.01.05 |
---|---|
TableViewController - 재사용셀 (dequeueReusableCell) (0) | 2025.01.05 |
UIStackView (0) | 2025.01.05 |
Table View Controller - 2탄 (실전편) (0) | 2025.01.05 |
TableViewController - Dynamic , Static (0) | 2025.01.05 |