TableView나 CollectionView에서 CustomCell을 XIB로 생성하게 되면 awakeFromNib()이라는 메서드가 생기게 된다.
쉽게 이 함수의 역할을 설명하자면 ViewController에서 viewDidLoad의 역할과 비슷하다고 생각하면 된다.
cell의 디자인을 해당 함수에 적용시켜놓으면 cell이 로드될때 보이게 된다.
이번 글에서는 awakeFromNib이 호출되는 시점과 prepareForReuse이 필요한 이유에 대해 알아보도록 하겠다.
awakeFromNib의 호출시점
원래 셀의 디자인과 데이터에 관련된 코드를 ViewContoller의 `tableView(_ tableView: , cellForRowAt indexPath: )`메서드에서 호출해서 사용했었다. 그러나, 이 함수는 셀이 스크롤 될때마다 실행된다.
만약 모든 셀의 디자인이 동일하다면 이 함수를 매번 셀을 생성할때마다 실행하는것은 비효율적일 것이다.
class UserTableViewCell: UITableViewCell {
// ...
// awakeFromNib()은 언제 실행될까?
override func awakeFromNib() {
super.awakeFromNib()
print(#function)
}
// configureData()는 언제 실행될까?
func configureData(row: Friends) {
print(#function)
profileImageView.backgroundColor = .brown
nameLabel.font = .boldSystemFont(ofSize: 30)
messageLabel.font = .systemFont(ofSize: 20)
// ...
}
}
이런식으로 configureData라는 함수를 만들어서 cellForRowAt에서 호출하면 위의 두 개의 메서드는 다음과 같이 호출된다.
awakeFromNib()
configureData(row:)
awakeFromNib()
configureData(row:)
awakeFromNib()
configureData(row:)
awakeFromNib()
configureData(row:)
awakeFromNib()
configureData(row:)
// 스크롤할 때
configureData(row:)
configureData(row:)
configureData(row:)
configureData(row:)
configureData(row:)
configureData(row:)
configureData(row:)
awakeFromNib 메서드는 뷰가 처음 나타났을 때 처음 실행되며, configureData메서드는 스크롤할때마다 매번 출력된다.
스크롤할때 awakeFromNib 메서드가 더이상 실행되지 않는 이유는 이미 생성된 셀을 재사용하기 때문이다. 즉, 스크롤하면서 보이는 셀들은 awakeFromNib 당시에 생성된 셀이 재사용되는 거라고 생각하면 된다.
이러한 이유 때문에 BackgroundColor이나 Font 등 셀마다 달라지지 않는 디자인 요소는 awakeFromNib에 작성해주는게 효율적일것이다.
// 바뀌지 않는 디자인을 담음
override func awakeFromNib() {
super.awakeFromNib()
print(#function)
configure()
}
// 바뀌지 않는 디자인
private func configure() {
profileImageView.backgroundColor = .brown
nameLabel.font = .boldSystemFont(ofSize: 30)
messageLabel.font = .systemFont(ofSize: 20)
}
// 셀마다 바뀌는 디자인
func configureData(row: Friends) {
print(#function)
nameLabel.text = row.name
messageLabel.text = row.message
let image = row.profile_image
if let image {
let url = URL(string: image)
profileImageView.kf.setImage(with: url)
} else {
profileImageView.image = UIImage(systemName: "person")
}
let name = row.like ? "heart.fill" : "heart"
let btn = UIImage(systemName: name)
likeButton.setImage(btn, for: .normal)
}
prepareForReuse의 필요성
셀에 들어갈 데이터를 조건문을 통해 100% 모든 경우의수를 처리하지 않으면 셀이 재사용될때 문제가 발생한다.
즉, 다음과 같이 url이 없을 경우 기본 person 이미지를 제공해주겠다는 else문을 삭제하면
let image = row.profile_image
if let image {
let url = URL(string: image)
profileImageView.kf.setImage(with: url)
}
// else {
// profileImageView.image = UIImage(systemName: "person")
// }
이런식으로 스크롤하고 난 이후에 다른 데이터가 들어오기도 한다.
이는 셀을 재사용하는 메커니즘때문에 발생하는 문제이다.
`prepareForReuse`의 경우 cell을 재사용할때 다른 컨텐츠를 넣어놓는게 아니라, 비워놓은 상태로 재사용할 수 있도록 만들어준다.
이 메서드가 실행되는 시점은 다음과 같다.
awakeFromNib()
configureData(row:)
awakeFromNib()
configureData(row:)
// 스크롤
prepareForReuse()
configureData(row:)
prepareForReuse()
configureData(row:)
처음 뷰가 나타나면 awakeFromNib메서드가 실행되지만, 스크롤하면 prepareForReuse메서드가 실행된다.
이 메서드에는 재사용할 셀의 기본값을 정해줄 수 있다.
override func prepareForReuse() {
super.prepareForReuse()
print(#function)
profileImageView.image = UIImage(systemName: "person")
}
이제 스크롤할때 재사용할 셀에 데이터가 없다면 기본값으로 person이미지가 들어가게 된다.
'iOS > UIKit' 카테고리의 다른 글
[iOS/UIKit] 프로젝트 트러블슈팅 (0) | 2025.01.28 |
---|---|
[iOS/UIKit] @objc와 #selector - 커스텀뷰에 addTarget을 하면 안되는 이유 (0) | 2025.01.15 |
[iOS / UIKit] Unwind - 맨 처음 뷰로 돌아가기 (0) | 2025.01.03 |
[iOS / UIKit] UserDefaults - 앱에 데이터 저장하기 (0) | 2025.01.02 |
[iOS / UIKit] AppDelegate와 SceneDelegate - 앱의 생명주기 (0) | 2024.12.29 |