iOS/Swift

왜 DispatchQueue.main을 tableView(_ : cellForRowAt: )에 안 넣었나?

밤새는 탐험가89 2024. 8. 20. 00:26

수정 전 


    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 작업이 이미 메인 스레드에서 안전하게 이루어지고 있기 때문입니다. 따라서 이 경우 추가적인 비동기 작업이 필요하지 않습니다.