수정 전
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeFeedTableViewCell.identifier, for: indexPath) as? HomeFeedTableViewCell else { return UITableViewCell() }
NetworkManager.shared.getAttractionData { results in
switch results{
case .success(let item):
print(item)
let address = item[indexPath.row].addr1
let originalTitle = item[indexPath.row].title
let modifiedTitle = originalTitle.removingParentheses()
let posterURL = item[indexPath.row].firstimage
// UI 업데이트는 메인 스레드에서 수행
DispatchQueue.main.async {
// cell.configure(with: modifiedTitle, address: address)
cell.configureWithImage(title: modifiedTitle, address: address, posterPath: posterURL ?? "")
}
case .failure(let error):
print(error.localizedDescription)
}
}
cell.selectionStyle = .none
return cell
}
수정 후
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeFeedTableViewCell.identifier, for: indexPath) as? HomeFeedTableViewCell else { return UITableViewCell() }
let item = attractionsWithImages[indexPath.row]
let address = item.addr1
let originalTitle = item.title
let modifiedtitle = originalTitle.removingParentheses()
let posterURL = item.firstimage ?? item.firstimage2 ?? ""
cell.configureWithImage(title: modifiedtitle, address: address, posterPath: posterURL)
cell.selectionStyle = .none
return cell
}
아래 코드는 API를 통해 받아오는 데이터 중에서 이미지가 있는 경우와 없는 경우가 있습니다.
이에 따라 별도의 배열을 생성하여 이미지 유무로 나누어 배열에 저장했습니다.
private func getAttractionData() {
NetworkManager.shared.getAttractionData { [weak self] results in
switch results {
case .success(let items):
// 이미지가 있는 항목과 없는 항목을 분리
self?.attractionsWithImages = items.filter { $0.firstimage?.count != 0 || $0.firstimage2?.count != 0 }
self?.attractionsWithoutImages = items.filter { $0.firstimage?.count == 0 && $0.firstimage2?.count == 0 }
// 메인 스레드에서 테이블 뷰 갱신
DispatchQueue.main.async {
self?.homeFeedTable.reloadData()
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
DispatchQueue.main이 왜 tableView(_:cellForRowAt:) 안에 없나요?
DispatchQueue.main.async는 비동기 작업을 메인 스레드에서 실행하도록 하는 코드입니다.
이 코드가 필요했던 이유는 네트워크 요청과 같은 비동기 작업이 완료된 후 UI를 업데이트할 때 반드시 메인 스레드에서 작업이 이루어져야 하기 때문입니다.
tableView(_:cellForRowAt:) 메서드 안에서는 이미 UI 작업이 이루어지는 메인 스레드에서 실행됩니다. cellForRowAt 메서드는 테이블 뷰가 데이터를 요청할 때 호출되며, 이 메서드 내에서 UI를 안전하게 업데이트할 수 있습니다.
따라서 이 메서드 내부에서는 DispatchQueue.main.async가 필요하지 않습니다.
그 대신, 네트워크 요청이 비동기적으로 완료된 후 테이블 뷰를 다시 로드하거나 데이터를 업데이트할 때 DispatchQueue.main.async를 사용해야 합니다. 이 작업은 네트워크 요청이 완료된 후 UI를 업데이트하기 위해 필요한 것입니다.
요약
DispatchQueue.main.async가 cellForRowAt 안에 없는 이유는, cellForRowAt 메서드 내에서 UI 작업이 이미 메인 스레드에서 안전하게 이루어지고 있기 때문입니다. 따라서 이 경우 추가적인 비동기 작업이 필요하지 않습니다.
'iOS > Swift' 카테고리의 다른 글
Swift에서 Any와 AnyObject의 차이점은 무엇인가요? (0) | 2024.08.23 |
---|---|
Storyboard와 XIB의 차이점은 무엇인가요? (0) | 2024.08.21 |
handshake failed at state 12288: not completed (0) | 2024.08.18 |
iOS 앱의 생명주기(App Life Cycle)에 대해 설명해주세요. (0) | 2024.08.16 |
Swift에서 옵셔널이란 무엇이며, 언제 사용해야 하나요? (0) | 2024.08.16 |