어제 테이블뷰의 셀 재사용에 대해 공부했는데, 셀이 화면 안에 모두 보여지는 경우는 문제가 없지만 스크롤을 해야 다음 셀이 보이는 경우에는 dequeueReusableCell
메서드로 더이상 보이지 않는 셀을 재사용해서 사용했었다.
그런데 이런 경우를 보자.
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
/// 섹션 수 반환
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
/// 섹션별 로우 수 반환
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 15
}
/// 인덱스에 해당하는 셀 반환
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
cell.textLabel?.text = "section \(indexPath.section), row: \(indexPath.row)"
if indexPath.section == 0 {
cell.textLabel?.textColor = UIColor.blue
} else if indexPath.section == 2 {
cell.textLabel?.textColor = UIColor.red
}
return cell
}
/// 섹션별 헤더 반환
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section) Header"
}
}
Section 0은 글자 색을 파란색으로, Section 1은 검은색으로, Section 2는 빨간색으로 만들어주었다.
스크롤을 내리거나 올릴 때 셀 재사용에 의해 우리의 의도와는 달리 색이 바뀐 셀이 재사용되면서 검은색이어야 할 Section 1의 색이 파랑/빨강색으로 나타나고 있다.
셀에 configure되는 데이터 소스의 내용은 바꿔치기되지만, 셀 자체는 재사용되기 때문에 셀의 content와 무관한 text color, alpha, editing, selection state 등 속성이 이전에 사용된 그대로 남아있는 것이다.
재사용될 셀의 속성을 초기화할 필요가 있다.
이는 UITableViewCell 클래스의 prepareForReuse 메소드로 수행한다.
하지만 우리의 TableViewController는 이미 UITableViewController 클래스를 상속받고 있고, 스위프트에서는 클래스의 다중상속이 불가능하기 때문에 UITableViewCell 클래스를 추가로 사용하기 위해선 새 클래스 파일을 생성해주어야 한다.
즉, 셀을 커스텀해주는 것이다.
Ctrl+N > Cocoa Touch Class > UITableViewCell 클래스를 상속받는 CustomTableViewCell 클래스 생성
스토리보드에서 셀을 잡고 [Identify Inspector]에서 CustomTableViewCell과 연결해준다.
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell
TableViewController
의 재사용 큐에서 셀을 받아올 때 우리의 커스텀셀 타입으로 받아오기 위해 코드에 as! CustomTableViewCell
을 추가해준다.
이제 CustomTableViewCell
로 와서 드디어 prepareForReuse 메소드를 오버라이드해줄 차례!
class CustomTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
self.textLabel?.textColor = UIColor.label
}
}
셀의 색을 기본 content의 색으로 초기화해준다.
시뮬레이터를 돌려보면 셀 초기화가 제대로 되면서 문제가 해결되었다!
순서가 잘 나타난 그림이 있어 덧붙인다.
dequeueReusableCell
이 호출되면 셀이 재사용 큐에서 꺼내져서 cellForRowAt
으로 가기 전에 prepareForReuse()
를 거치므로 셀이 초기화된 후에 재사용되게 되는 것이다 ☺️
Data Container 디렉토리는 애플리케이션 설치 후 처음 구동할 때 생성되기 때문에, 코드를 작성하는 순간에는 디렉토리의 실제 위치를 알기 어렵다.
따라서 Data Container와 관련된 디렉토리를 쉽게 찾아갈 수 있는 방법을 Foundation 프레임워크에서 제공하며, 그 방법이 바로 FileManager를 활용하는 것이다.
이 FileManager를 활용해 특정 파일을 특정 디렉토리에 저장하거나 불러오기 위해 필요한 경로를 만드는 코드는 다음과 같다.
FileManager.default.url(for: FileManager.SearchPathDirectory.applicationSupportDirectory,
in: FileManager.SearchPathDomainMask.userDomainMask,
appropriateFor: nil,
create: true).appendingPathComponent("todos.json")
하나하나 뜯어보자.
우선 FileManager.default
로 파일매니저 인스턴스를 만들어준다. default를 붙여주면 싱글톤 인스턴스로 만들어진다고 한다.
url 메소드의 정의부를 보면 다음과 같다.
func url(for directory: FileManager.SearchPathDirectory,
in domain: FileManager.SearchPathDomainMask,
appropriateFor url: URL?,
create shouldCreate: Bool) throws -> URL
directory
: 탐색할 디렉토리 지정domain
: 이 이상은 못 가게 제한을 걸어주는 도메인 요소url
: 반환된 url의 위치를 결정하는 데 사용되는 파일 urlshouldCreate
: 디렉토리가 아직 없는 경우 생성할지 여부appendingPathComponent는 경로를 추가하는 역할을 한다. 아래 코드를 보면 단번에 이해가 갈 것이다.
let oldURL = URL(string: "~/Document")
let newURL = documentsURL.appendingPathComponent("Hello")
print(newURL)
// ~/Document/Hello
각각의 디렉토리가 어떤 역할을 하는지도 알아보자.
Documents
Inbox
Library
Application Support
Caches
Preferences
tmp
참고
Youtube | iOS Academy
Git Blog | 유셩장
Git Blog | Jiseob Kim
Git Blog | jinshine
Velog | Youngwoo Lee