[iOS] UITableViewCell의 재사용에 의한 이벤트 처리 문제

!·2023년 3월 1일
0

iOS

목록 보기
17/22

Overview

프로젝트(한 번 Voca)의 단어장 셀을 구현하면서, 테이블 뷰의 재사용 큐에 의한 문제를 마주했다. 애플 측에서 테이블 뷰 자체의 성능을 높히기위해, 화면내에서 사라진 테이블 뷰 셀이 다시 재활용되어 새로운 셀을 구성하는 재사용 큐 개념을 도입했다. 다만, 셀 내부의 서브 뷰들도 재활용이 함께 이루어지기때문에 이에 대한 처리를 확실하게 해주어야한다. 우선, 재활용 큐에 대해 한 번 알아보자.


재활용 큐

만약, 재활용 큐라는 개념이 없다고 생각해보자. 즉 매 스크롤 이벤트 발생시마다 셀 객체를 메모리에 올리고, 레이아웃을 구성한다면 이는 엄청난 낭비로 이어진다. 개수만큼의 셀 객체를 생성해주어야하니 말이다. 따라서, 애플은 재활용 큐라는 개념을 도입했다.

테이블 뷰에 재활용 큐를 등록하면, 일정한 개수의 셀 객체가 큐에 저장된다. 그리고 UITableViewDataSource 프로토콜의 메소드인 cellForRowAt 에서 셀 객체를 return 할때, 재활용 큐에서 꺼낸다. 그리고 스크롤하면서 사라진 셀들은 다시 큐에 들어오게된다. 이는 일정한 개수의 셀 객체만 메모리에 올림으로써, 셀 객체를 다시 생성하는 자원 낭비를 하지 않게된다.


어떤 문제?

나는 UITableViewCell을 상속해 커스텀 셀을 만들었다. 또한 각 셀 내부에 서브 뷰(버튼, 레이블)등을 구성하였다. 문제는 셀들이 재활용이 되면서 서브 뷰 또한 재사용된다는 것이다. 따라서, 버튼을 클릭 한 셀이 화면이 위로 올라감으로써 사라지고 새로운 셀을 구성하기 위해 다시 사용된다면 버튼을 클릭 한 상태로 나타나게 된다.


해결 방법

첫번째 해결방법은 재사용 셀이 다시 화면에 나타나기전에 전처리 메소드를 이용하는 것이다.

cellForRowAt 메소드에서 셀이 리턴되기 전에, prepareForReuse() 메소드가 수행된다. 이 때, 이 메소드를 override 해서 다시 나타나는 셀들을 초기화시켜주는 것이다.

override func prepareForReuse(){
	self.title = nil
    self.button = nil
}

두번째 해결방법은 Delegate 패턴을 이용해 CellForRowAt 메소드에서 셀을 초기화시켜주는 것이다. 첫번째 해결방법은 셀 내부에서 비즈니스 로직을 처리하므로, MVC 패턴을 채택해 프로젝트를 진행하기때문에 고려하지 않았다. VC 내부에서 비즈니스 로직을 처리한다면 두번째 해결방법이 적합할 것 같다.

protocol CellDelegate {
	func didTouched(_sender: UIButton)
}

class CustomCell: UITableViewCell{

	var delegate = CellDelegate?
	
	@objc func buttonTouched(_ sender: UIButton){
    	// 버튼 기능 구현
    	delegate?.didTouched()
		self.setButton(true)
	}

	func setButton(_ on: bool){
    	// 버튼을 터치된 상태로?
	}
}

class ViewController: UITableViewDelegate, CellDelegate{
	
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    	let cell = dequeueReusable(identifier: "asd") as! CustomCell
        cell.delegate = self
	
        if isTouched == true{
			cell.setButton(true)
		}else{
			cell.setButton(false)
		}
    }
	
    override func didTouched(_ sender: UIButton){
		
    }
}

번외로 tableView.cellForRow(at) 메소드로 셀을 얻어와 커스텀 타입으로 캐스팅 후, 처리해보는 방식도 고려해보았지만 이 경우에도 얻은 셀이 테이블 뷰 내에 여러 개 존재하면 마찬가지로 동일한 문제가 발생했다.


참고 자료

https://lsh424.tistory.com/63
https://jiseok-zip.tistory.com/entry/iOSdequeueReusableCellWithIdentifier-%EC%85%80-%EC%9E%AC%EC%82%AC%EC%9A%A9

profile
개발자 지망생

0개의 댓글