Diffable DataSource 적용


초기 테이블뷰 구성할 때, 그리고 검색 작업을 수행함에 따라 모델 데이터에 append가 발생했을 때 애니메이션을 적용

private func apply() {
    let cities = model.cities
    var snapshot = NSDiffableDataSourceSnapshot<Section, AnotherCity>()
    snapshot.appendSections([.main])
    snapshot.appendItems(cities)
    dataSource.apply(snapshot, animatingDifferences: true)
}
    
private func configureDataSource() {
    dataSource = UITableViewDiffableDataSource<Section, AnotherCity>(tableView: cityWeatherTableView) { [weak self] (tableView: UITableView, indexPath: IndexPath, itemIdentifier: AnotherCity) -> UITableViewCell? in
        // configure and return cell
        guard let cell = tableView.dequeueReusableCell(withIdentifier: CityWeatherTableViewCell.identifier, for: indexPath) as? CityWeatherTableViewCell, let self = self else { return nil }
        let currentWeather = self.model.cities[indexPath.row].currentWeather
        let forecastWeather = self.model.cities[indexPath.row].forecastWeather
            
        // 즐겨찾기 버튼 설정
        for index in self.storedCities.indices {
            if indexPath.row < self.model.count, currentWeather.name == self.storedCities[index] {
                cell.bookmarkButton.isSelected = true
                cell.bookmarkButton.tintColor = .systemYellow
                break
            }
        }
            
        // 날씨 데이터 설정
        cell.cityNameLabel.text = currentWeather.name
        cell.weatherLabel.text = currentWeather.weather[.zero].description
        cell.temperatureLabel.text = String(Int(currentWeather.main.temp)) + AppText.celsiusString
        cell.setUpForecast(forecast: forecastWeather)
        return cell
    }
}

네트워크 통신 작업 그룹화


네트워크 통신 작업을 그룹화하여 기존에 optional로 사용하던 엔티티의 프로퍼티들을 non-optional로 교체하고, 그에 따라 불필요해진 함수들 삭제. view controller의 코드 복잡성 또한 감소시킴.

private func requestCityWeather(_ cityName: String) async {
    guard let currentWeatherURL = networkManager.getCurrentWeatherURL(with: cityName),
            let forecastWeatherURL = networkManager.getForecastURL(with: cityName) else { return }
        
    guard let currentWeather = await requestCurrentWeather(with: currentWeatherURL),
            let forecastWeather = await requestForecast(with: forecastWeatherURL) else { return }
        
    let city = AnotherCity(name: cityName, currentWeather: currentWeather, forecastWeather: forecastWeather)
    model.appendCity(city)
    apply()
}