diff --git a/SOPT33_assignment2/SOPT33_assignment2.xcodeproj/project.pbxproj b/SOPT33_assignment2/SOPT33_assignment2.xcodeproj/project.pbxproj index 76edfb4..140fd63 100644 --- a/SOPT33_assignment2/SOPT33_assignment2.xcodeproj/project.pbxproj +++ b/SOPT33_assignment2/SOPT33_assignment2.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 834960C12B011B6500A78244 /* WeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834960C02B011B6500A78244 /* WeatherService.swift */; }; 834960C32B011D2A00A78244 /* OpenWeatherData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834960C22B011D2A00A78244 /* OpenWeatherData.swift */; }; 834960C82B025AF800A78244 /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834960C72B025AF800A78244 /* NetworkError.swift */; }; + 835293BE2B30874600043B67 /* WeatherListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835293BD2B30874600043B67 /* WeatherListViewModel.swift */; }; 835E9E492AFBEE0300D5E4C5 /* HourCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835E9E482AFBEE0300D5E4C5 /* HourCollectionViewCell.swift */; }; 835E9E4B2AFCCB8200D5E4C5 /* CustomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835E9E4A2AFCCB8200D5E4C5 /* CustomHeaderView.swift */; }; 838AA6832ADB93AF00CC766B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 838AA6822ADB93AF00CC766B /* AppDelegate.swift */; }; @@ -53,6 +54,7 @@ 834960C22B011D2A00A78244 /* OpenWeatherData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenWeatherData.swift; sourceTree = ""; }; 834960C62B012BDB00A78244 /* Secrets.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Secrets.xcconfig; sourceTree = ""; }; 834960C72B025AF800A78244 /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; + 835293BD2B30874600043B67 /* WeatherListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherListViewModel.swift; sourceTree = ""; }; 835E9E482AFBEE0300D5E4C5 /* HourCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HourCollectionViewCell.swift; sourceTree = ""; }; 835E9E4A2AFCCB8200D5E4C5 /* CustomHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomHeaderView.swift; sourceTree = ""; }; 838AA67F2ADB93AF00CC766B /* SOPT33_assignment2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SOPT33_assignment2.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -98,7 +100,82 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 834960812AFD4B3900A78244 /* FirstSection */ = { + 834960C92B025B1400A78244 /* Network */ = { + isa = PBXGroup; + children = ( + 83FEC0532B1F7D3600D91AE4 /* Service */, + 83FEC0522B1F7D2F00D91AE4 /* Data */, + 834960C72B025AF800A78244 /* NetworkError.swift */, + ); + path = Network; + sourceTree = ""; + }; + 835293A12B2C3AE700043B67 /* Presentation */ = { + isa = PBXGroup; + children = ( + 835293A22B2C3AF100043B67 /* WeatherList */, + 835293A32B2C3B1200043B67 /* DetailWeatherList */, + ); + path = Presentation; + sourceTree = ""; + }; + 835293A22B2C3AF100043B67 /* WeatherList */ = { + isa = PBXGroup; + children = ( + 835293BB2B303CBE00043B67 /* ViewModel */, + 835293A42B2C3B2000043B67 /* View */, + 835293A52B2C3B2500043B67 /* ViewController */, + ); + path = WeatherList; + sourceTree = ""; + }; + 835293A32B2C3B1200043B67 /* DetailWeatherList */ = { + isa = PBXGroup; + children = ( + 835293BC2B303CC900043B67 /* ViewModel */, + 835293A72B2C3B3500043B67 /* View */, + 835293A62B2C3B2E00043B67 /* ViewController */, + ); + path = DetailWeatherList; + sourceTree = ""; + }; + 835293A42B2C3B2000043B67 /* View */ = { + isa = PBXGroup; + children = ( + 83FEC0562B20E7B200D91AE4 /* WeatherListView.swift */, + 8394798A2AEFC31B00DE7A90 /* WeatherListTableViewCell.swift */, + ); + path = View; + sourceTree = ""; + }; + 835293A52B2C3B2500043B67 /* ViewController */ = { + isa = PBXGroup; + children = ( + 838AA6862ADB93AF00CC766B /* ViewController.swift */, + ); + path = ViewController; + sourceTree = ""; + }; + 835293A62B2C3B2E00043B67 /* ViewController */ = { + isa = PBXGroup; + children = ( + 838AA6A62ADD79C100CC766B /* ResultViewController.swift */, + ); + path = ViewController; + sourceTree = ""; + }; + 835293A72B2C3B3500043B67 /* View */ = { + isa = PBXGroup; + children = ( + 83FEC0542B1F91B300D91AE4 /* DetailWeatherList.swift */, + 835293A82B2C3B9100043B67 /* FirstSection */, + 835293A92B2C3B9B00043B67 /* SecondSection */, + 835293AA2B2C3BA900043B67 /* ThirdSection */, + ); + path = View; + sourceTree = ""; + }; + 835293A82B2C3B9100043B67 /* FirstSection */ = { isa = PBXGroup; children = ( 83DCC7B72AF8D270000EC679 /* TopCollectionViewCell.swift */, @@ -106,7 +183,7 @@ path = FirstSection; sourceTree = ""; }; - 834960822AFD4B4400A78244 /* SecondSection */ = { + 835293A92B2C3B9B00043B67 /* SecondSection */ = { isa = PBXGroup; children = ( 83DCC7B92AF8D549000EC679 /* TimeWeatherCollectionViewCell.swift */, @@ -117,7 +194,7 @@ path = SecondSection; sourceTree = ""; }; - 834960832AFD4B5800A78244 /* ThirdSection */ = { + 835293AA2B2C3BA900043B67 /* ThirdSection */ = { isa = PBXGroup; children = ( 8394799C2AF4A97800DE7A90 /* DayWeatherCollectionViewCell.swift */, @@ -127,14 +204,19 @@ path = ThirdSection; sourceTree = ""; }; - 834960C92B025B1400A78244 /* Network */ = { + 835293BB2B303CBE00043B67 /* ViewModel */ = { isa = PBXGroup; children = ( - 83FEC0532B1F7D3600D91AE4 /* Service */, - 83FEC0522B1F7D2F00D91AE4 /* Data */, - 834960C72B025AF800A78244 /* NetworkError.swift */, + 835293BD2B30874600043B67 /* WeatherListViewModel.swift */, ); - path = Network; + path = ViewModel; + sourceTree = ""; + }; + 835293BC2B303CC900043B67 /* ViewModel */ = { + isa = PBXGroup; + children = ( + ); + path = ViewModel; sourceTree = ""; }; 838AA6762ADB93AF00CC766B = { @@ -157,12 +239,11 @@ 838AA6812ADB93AF00CC766B /* SOPT33_assignment2 */ = { isa = PBXGroup; children = ( + 835293A12B2C3AE700043B67 /* Presentation */, 83FEC0422B1E158200D91AE4 /* Application */, 83FEC0432B1E159800D91AE4 /* Global */, 834960C92B025B1400A78244 /* Network */, 83FEC04C2B1F7B3400D91AE4 /* Model */, - 83FEC04A2B1F7AD700D91AE4 /* VC */, - 83FEC04B2B1F7B1500D91AE4 /* Cell */, 838AA68D2ADB93B100CC766B /* LaunchScreen.storyboard */, 838AA6902ADB93B100CC766B /* Info.plist */, ); @@ -213,24 +294,6 @@ path = Global; sourceTree = ""; }; - 83FEC04A2B1F7AD700D91AE4 /* VC */ = { - isa = PBXGroup; - children = ( - 838AA6862ADB93AF00CC766B /* ViewController.swift */, - 838AA6A62ADD79C100CC766B /* ResultViewController.swift */, - ); - path = VC; - sourceTree = ""; - }; - 83FEC04B2B1F7B1500D91AE4 /* Cell */ = { - isa = PBXGroup; - children = ( - 83FEC04F2B1F7B8900D91AE4 /* WeatherList */, - 83FEC04E2B1F7B7F00D91AE4 /* DetailWeatherList */, - ); - path = Cell; - sourceTree = ""; - }; 83FEC04C2B1F7B3400D91AE4 /* Model */ = { isa = PBXGroup; children = ( @@ -240,26 +303,6 @@ path = Model; sourceTree = ""; }; - 83FEC04E2B1F7B7F00D91AE4 /* DetailWeatherList */ = { - isa = PBXGroup; - children = ( - 83FEC0542B1F91B300D91AE4 /* DetailWeatherList.swift */, - 834960812AFD4B3900A78244 /* FirstSection */, - 834960822AFD4B4400A78244 /* SecondSection */, - 834960832AFD4B5800A78244 /* ThirdSection */, - ); - path = DetailWeatherList; - sourceTree = ""; - }; - 83FEC04F2B1F7B8900D91AE4 /* WeatherList */ = { - isa = PBXGroup; - children = ( - 8394798A2AEFC31B00DE7A90 /* WeatherListTableViewCell.swift */, - 83FEC0562B20E7B200D91AE4 /* WeatherListView.swift */, - ); - path = WeatherList; - sourceTree = ""; - }; 83FEC0502B1F7C6C00D91AE4 /* DetailWeatherList */ = { isa = PBXGroup; children = ( @@ -401,6 +444,7 @@ 834960C82B025AF800A78244 /* NetworkError.swift in Sources */, 835E9E4B2AFCCB8200D5E4C5 /* CustomHeaderView.swift in Sources */, 834960C12B011B6500A78244 /* WeatherService.swift in Sources */, + 835293BE2B30874600043B67 /* WeatherListViewModel.swift in Sources */, 834960802AFD42E300A78244 /* CustomFooterView.swift in Sources */, 838AA6832ADB93AF00CC766B /* AppDelegate.swift in Sources */, 835E9E492AFBEE0300D5E4C5 /* HourCollectionViewCell.swift in Sources */, diff --git a/SOPT33_assignment2/SOPT33_assignment2/Presentation/WeatherList/ViewController/ViewController.swift b/SOPT33_assignment2/SOPT33_assignment2/Presentation/WeatherList/ViewController/ViewController.swift index 6039852..cb4f21c 100644 --- a/SOPT33_assignment2/SOPT33_assignment2/Presentation/WeatherList/ViewController/ViewController.swift +++ b/SOPT33_assignment2/SOPT33_assignment2/Presentation/WeatherList/ViewController/ViewController.swift @@ -12,141 +12,86 @@ import Then final class ViewController: UIViewController, UISearchControllerDelegate { + // MARK: - set Properties - + var searchWeatherListData = weatherList //검색 결과 데이터 private var weatherListView : WeatherListView? - + var weatherListViewModel = WeatherListViewModel() + // MARK: - Life Cycle - + override func viewDidLoad() { super.viewDidLoad() - - //api key test - guard let apiKey = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String else { return } - print(apiKey) - - Task { - await fetchWeatherInfo() - } - + setWeatherListView() - - setupNavigation() - setDelegate() + setNavigation() setTableViewConfig() + + setDelegate() + bindViewModel() } - - @objc func buttonPressed() { - let resultVC = ResultViewController() // ResultViewController 초기화 - navigationController?.pushViewController(resultVC, animated: true) // 화면에 표시 - } - - - // MARK: - set Navigation - - func setupNavigation() { - self.navigationItem.searchController = weatherListView?.searchController - self.navigationController?.navigationBar.prefersLargeTitles = true - self.navigationItem.title = "날씨" - self.navigationItem.hidesSearchBarWhenScrolling = false + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(true) + loadData() } - // MARK: - set WeatherList View - + private func setWeatherListView() { weatherListView = WeatherListView(frame: view.bounds) if let resultView = weatherListView { view.addSubview(resultView) resultView.configure() } - // 검색 - weatherListView?.searchController.searchResultsUpdater = self + self.weatherListView?.searchController.searchResultsUpdater = self } - - // MARK: - set Delegate - private func setDelegate() { - weatherListView?.tableView.delegate = self - weatherListView?.tableView.dataSource = self + // MARK: - set Navigation + + func setNavigation() { + self.navigationItem.searchController = weatherListView?.searchController + self.navigationController?.navigationBar.prefersLargeTitles = true + self.navigationItem.title = "날씨" + self.navigationItem.hidesSearchBarWhenScrolling = false } // MARK: - set TableView - + private func setTableViewConfig() { weatherListView?.tableView.register(WeatherListTableViewCell.self, forCellReuseIdentifier: WeatherListTableViewCell.className) } - - // MARK: - Network - - //API에서 가져오는 timezone 현재 시간으로 변경하기 - func convertTime(timezone: Int) -> String { - let timeZone = TimeZone(secondsFromGMT: timezone) - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "HH:mm" - dateFormatter.timeZone = timeZone - let currentDate = Date() - let formattedTime = dateFormatter.string(from: currentDate) - return formattedTime - } - - private func fetchWeatherInfo() async { - let cityname = ["seoul", - "daegu", - "ulsan", - "chuncheon", - "jeju", - "gwangju", - "suwon", - "iksan", - "busan"] - - for city in cityname { - do { - let currentWeather = try await WeatherService.shared.getWeatherData(cityname: city) - print("type:", type(of: currentWeather.timezone)) - let weatherInfo = WeatherListData(location: currentWeather.name, - time: convertTime(timezone: currentWeather.timezone), - weather: currentWeather.weather[0].main, - temperature: Int(currentWeather.main.temp), - max: Int(currentWeather.main.tempMax), - min: Int(currentWeather.main.tempMin)) - weatherList.append(weatherInfo) - searchWeatherListData = weatherList - } catch { - print(error) - } - } - weatherListView?.tableView.reloadData() - } -} + // MARK: - set Delegate -extension ViewController: UITableViewDelegate {} -extension ViewController: UITableViewDataSource { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return searchWeatherListData.count + private func setDelegate() { + weatherListView?.tableView.delegate = self } + - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: WeatherListTableViewCell.className, - for: indexPath) as? WeatherListTableViewCell else {return UITableViewCell()} - - cell.bindData(data: searchWeatherListData[indexPath.row]) - return cell + // MARK: - binding ViewModel + + private func bindViewModel() { + self.weatherListView?.tableView.dataSource = weatherListViewModel + self.weatherListView?.tableView.reloadData() } +} + +// Cell 클릭 시 화면 이동 +extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) print("Click Cell Number:" + String(indexPath.row)) - buttonPressed() + let resultVC = ResultViewController() + navigationController?.pushViewController(resultVC, animated: true) } } @@ -163,3 +108,15 @@ extension ViewController: UISearchResultsUpdating { weatherListView?.tableView.reloadData() } } + +// 날씨 데이터 +extension ViewController { + private func loadData() { + Task { + let success = await weatherListViewModel.fetchWeatherInfo() + if success { + self.weatherListView?.tableView.reloadData() + } + } + } +}