본문 바로가기
iOS/설명

[iOS] performBatchUpdates

by Sky Titan 2022. 4. 24.
728x90
 

[iOS] - UITableView performBatchUpdates - row와 section를 일괄적으로 업데이트하기

Row와 Section을 일괄적으로 업데이트하는 방법에 대해 알아보자.

yoojin99.github.io

 

Apple Developer Documentation

 

developer.apple.com

performBatchUpdates

  • UITableView와 UICollectionView에서 insert, delete, reload, move 등의 동작들의 애니메이션을 group화해서 동시에 실행할 수 있게 해주는 메소드이다
  • beginUpdates(), endUpdates()와 같이 batch update를 적용할 수 있는 방법 중에 하나이며, 애플 공식문서에서는 beginUpdates(), endUpdates() 대신 performBatchUpdates를 사용할 것을 권장하고 있다.
  • 주의사항
    • 해당 메서드를 호출하기 전에, TableView 혹은 CollectionView의 레이아웃이 업데이트 되어있지 않다면 reload가 일어날 수 있기 때문에, 이 메서드를 호출하기 전에 항상 레이아웃이 업데이트되어있게 하거나 'updates' block안에서 데이터 모델을 업데이트 해야 한다.
    • batch 오퍼레이션에서 delete는 insert가 실행되기 전에 먼저 실행된다. 그렇기 때문에 insert 뒤에 delete를 실행할 때 index는 insert가 되기 전 상황을 기준으로 계산해야 한다. (beginUpdates, endUpdates 사용 시에도 마찬가지)
Parameter description
updates insert, delete, reload, move 오퍼레이션을 실행하는 block이다.
completion - 모든 오퍼레이션이 끝나고 실행되는 completion 핸들러 블록이다.

- 해당 block은 Boolean 파라미터를 하나 가지고 있는데, 해당 값이 true면 모든 애니메이션이 정상적으로 종료되었다는 뜻이고, false이면 어떤 이유에서든 간에 애니메이션이 정상적으로 완료되지 못했다는 뜻이다.

- completion파라미터는 nil이 될 수 있다.

 

delete, insert 동시 사용 시 주의

class ViewController: TSViewController {

    @IBOutlet weak var tableView: UITableView!
    var stringList: [String] = ["Hello", "World"] //시작할 땐 2개의 item
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UINib(nibName: "TestCell", bundle: Bundle.main), forCellReuseIdentifier: "testCell")
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = UITableView.automaticDimension
        tableView.reloadData()
    }
    
    @IBAction func performClick(_ sender: Any) {
        tableView.performBatchUpdates({
            stringList.insert("new", at: 0) //1개의 item을 더 추가해서 dataSource인 stringList의 아이템 개수는 총 3개가 된다.
            tableView.insertRows(at: [[0, 0]], with: .fade)
            
            stringList.remove(at: 2)//맨 마지막 index의 아이템을 지운다.
            tableView.deleteRows(at: [[0, 2]], with: .fade)// Crash: attempt to delete row 2 from section 0 which only contains 2 rows
        })
    }
    
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "testCell", for: indexPath) as! TestCell
        cell.label.text = stringList[indexPath.row]
        return cell
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        stringList.count
    }
}

 위에서 설명했듯이 deleteRows가 배치에서 먼저 실행되기 때문에 insert를 코드상에선 먼저 실행하더라도 크래시가 발생한다.

 정상적으로 삭제하려면 아래와 같이 작성해야 한다.

 

tableView.performBatchUpdates({
            stringList.insert("new", at: 0) //1개의 item을 더 추가해서 dataSource인 stringList의 아이템 개수는 총 3개가 된다.
            tableView.insertRows(at: [[0, 0]], with: .fade)
            
            stringList.remove(at: 2)//맨 마지막 index의 아이템을 지운다.
            tableView.deleteRows(at: [[0, 1]], with: .fade)//dataSource에는 3개의 아이템이 존재하더라도 배치상 delete가 먼저 실행되기 때문에 2개의 아이템을 기준으로 삭제할 index를 계산
        })

728x90

'iOS > 설명' 카테고리의 다른 글

[iOS] Push Notification callback함수들  (1) 2022.04.24
[iOS] UIView.transition  (0) 2022.04.24
[iOS] json파일 dictionary로 불러오기  (0) 2022.04.22
[iOS] Bundle  (0) 2022.04.22
[iOS] 앱 terminate되게 하는 법  (0) 2022.04.22

댓글