Skip to content

핵심 기능 개발 완료#1

Open
TyrHanz wants to merge 8 commits into
mainfrom
develop
Open

핵심 기능 개발 완료#1
TyrHanz wants to merge 8 commits into
mainfrom
develop

Conversation

@TyrHanz

@TyrHanz TyrHanz commented Feb 20, 2026

Copy link
Copy Markdown
Owner

No description provided.

- 메인도시 이름 및 현재온도, 최소/최대온도, 날씨 이미지 표기 뷰 구현
- 현재시간 API 값과 연동되는 Model 생성
- API 연결 메소드 구현
- ViewModel 생성 및 API 연결 메소드 추가
- ImageIcon 호출 코드 추가(이슈: 해당 사이트에서 샘플 이미지 한개를 제외하고 전체 사용불가, 임시로 하나만 로드하게 해놓음)
- 과거 날씨 정보 모델 추가
- 과거 날씨 API 로직 추가
- 과거 날씨 출력 뷰 생성
- 메인 뷰에서 날씨 정보를 나타내는 컴포넌트를 컬랙션 뷰에 삽입 및 전홤 표출
- 과거 정보 표기 추가
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @godzx3-ctrl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 날씨 예측 애플리케이션의 핵심 기능 개발을 완료합니다. 외부 라이브러리(SnapKit, Then)를 통합하고, OpenWeather API를 통해 날씨 데이터를 가져오고 표시하기 위한 데이터 모델, 서비스 계층, UI 컴포넌트 및 뷰 모델을 포함하는 구조화된 아키텍처를 구현합니다. 이를 통해 현재 날씨 정보와 여러 날의 예보를 효율적으로 관리하고 사용자에게 제공할 수 있습니다.

Highlights

  • API 키 관리: .gitignore 파일에 API 키 파일을 추가하여 민감한 정보가 Git 추적에서 제외되도록 했습니다.
  • 외부 라이브러리 통합: UI 레이아웃을 위한 SnapKit과 코드 가독성 향상을 위한 Then Swift 패키지가 Xcode 프로젝트에 통합되었습니다.
  • 날씨 데이터 모델 정의: OpenWeather API 응답을 처리하기 위한 CurrentWeatherModel 및 ForecastWeatherModel Decodable 구조체가 추가되었습니다.
  • 날씨 API 서비스 구현: OpenWeatherAPIService 클래스를 통해 현재 날씨 및 예보 데이터를 가져오는 기능이 구현되었습니다.
  • 날씨 정보 UI 컴포넌트 개발: 현재 날씨와 예보를 표시하기 위한 CurrentWheatherCell, CurrentWheatherView, ForecastCell, ForecastView 등 다양한 UI 컴포넌트가 생성되었습니다.
  • 메인 뷰 컨트롤러 리팩토링: 기존 ViewController를 제거하고, UICollectionView와 compositional layout을 사용하여 날씨 정보를 동적으로 표시하며 MainViewModel과 연동되는 새로운 ViewController를 구현했습니다.
Changelog
  • .gitignore
    • API 키 파일을 무시 목록에 추가했습니다.
  • weatherForecastApp/weatherForecastApp.xcodeproj/project.pbxproj
    • SnapKit과 Then Swift 패키지 종속성을 추가했습니다.
  • weatherForecastApp/weatherForecastApp/Model/CurrentWeatherModel.swift
    • 현재 날씨 데이터를 위한 Decodable 구조체를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/Model/ForecastWeatherModel.swift
    • 예보 날씨 데이터를 위한 Decodable 구조체를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/Service/OpenWeatherAPIService.swift
    • OpenWeatherMap API 호출을 위한 서비스 클래스를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/View/CurrentWheatherCell.swift
    • 현재 날씨 정보를 표시하는 UICollectionViewCell을 추가했습니다.
  • weatherForecastApp/weatherForecastApp/View/CurrentWheatherView.swift
    • 현재 날씨 세부 정보를 표시하는 UIView를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/View/ForecastCell.swift
    • 예보 날씨 정보를 표시하는 UICollectionViewCell을 추가했습니다.
  • weatherForecastApp/weatherForecastApp/View/ForecastView.swift
    • 개별 예보 항목을 표시하는 UIView를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/ViewController.swift
    • 초기 ViewController 파일을 제거했습니다.
  • weatherForecastApp/weatherForecastApp/ViewController/ViewController.swift
    • UICollectionView와 MainViewModel을 통합한 새로운 ViewController를 추가했습니다.
  • weatherForecastApp/weatherForecastApp/ViewModel/MainViewModel.swift
    • 날씨 데이터 가져오기 및 UI 업데이트를 처리하는 ViewModel을 추가했습니다.
Activity
  • 이 풀 리퀘스트에 대한 활동은 아직 없습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 날씨 예보 앱의 핵심 기능인 현재 및 예보 날씨 데이터 가져오기 및 표시를 구현합니다. MVVM을 사용한 전반적인 구조는 좋지만, 코드 스타일, 정확성, 성능 측면에서 몇 가지 개선할 점이 있습니다. 주요 문제점으로는 네이밍 오타, 이미지 네트워크 요청의 잘못된 처리, ViewController에서의 잠재적인 메모리 누수 등이 있습니다. 이러한 점들을 해결하기 위한 구체적인 제안을 남겼습니다.

Comment on lines +69 to +73
if let data = try? Data(contentsOf: imageUrl) {
if let image = UIImage(data: data) {
self.mainImage = image
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Data(contentsOf:)는 동기적으로 네트워크 요청을 수행하여 현재 스레드를 차단합니다. 이 코드는 백그라운드 스레드에서 실행되지만, 여전히 스레드를 차단하는 것은 좋지 않은 방식이며 성능 저하를 유발할 수 있습니다. URLSession.dataTask를 사용하여 이미지를 비동기적으로 로드해야 합니다.

            self.openApi.loadImage(url: imageUrl) { [weak self] data in
                guard let self = self, let data = data, let image = UIImage(data: data) else {
                    return
                }
                self.mainImage = image
                DispatchQueue.main.async {
                    self.UpdateCurrentUIClousure?()
                }
            }

Comment on lines +63 to +67
guard let imageUrl = URLComponents(string: "https://openweathermap.org/payload/api/media/file/10d@2x.png")?.url else
{
print("Create URL Failed")
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

이미지 URL이 하드코딩되어 있어 항상 같은 날씨 아이콘이 표시됩니다. 이는 버그입니다. API 응답으로 받은 weather 데이터의 icon 프로퍼티를 사용하여 동적으로 이미지 URL을 생성해야 합니다. 올바른 URL 형식은 https://openweathermap.org/img/wn/{icon_id}@2x.png 입니다.

            guard let iconId = result.weather.first?.icon,
                  let imageUrl = URL(string: "https://openweathermap.org/img/wn/\(iconId)@2x.png") else

Comment on lines +66 to +75
vm.UpdateCurrentUIClousure = { [weak self] in
guard let self else { return }
cell.currentWheatherView.UpdateUIData (
cityName: vm.currentWheaterModel?.name ?? "",
currentTemp: vm.currentWheaterModel?.main.temp ?? 0.0,
minTemp: vm.currentWheaterModel?.main.tempmin ?? 0.0,
maxTemp: vm.currentWheaterModel?.main.tempmax ?? 0.0,
image: vm.mainImage
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

cellForItemAt 메소드 내에서 vm.UpdateCurrentUIClousure를 할당하는 것은 메모리 누수 및 예기치 않은 동작을 유발할 수 있습니다. 셀이 재사용될 때마다 클로저가 cell을 강하게 참조하면서 계속 새로 할당되기 때문입니다. 이 바인딩 로직은 viewDidLoad와 같은 곳에서 한 번만 설정되어야 합니다.

Comment on lines +15 to +36
case currentWheatherView
/// 과거 날씨 뷰
case ForecastView
}

// MARK: - Closures
/// 현재 날씨 UI 업데이트 요청 클로저
var UpdateCurrentUIClousure: (()-> Void)?
/// 과거 날씨 UI 업데이트 요청 클로저
var UpdateForecastUIClosure: (()-> Void)?

//MARK: - Properties
/// API 클래스
let openApi = OpenWeatherAPIService()
/// 현재 정보 모델
var currentWheaterModel: CurrentWeatherModel? = nil
/// 과거 정보 모델
var forecastWheaterModel: ForecastWeatherModel? = nil
/// 기상 이미지
var mainImage: UIImage? = nil
/// 뷰 타입 지정
var viewTypes: [ViewType] = [.currentWheatherView, .ForecastView]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

프로퍼티와 열거형 케이스 이름에 오타가 여러 군데 있습니다. (currentWheatherView, currentWheaterModel, forecastWheaterModel). Weather의 철자가 Wheather 또는 Wheater로 잘못 사용되었습니다. 일관성과 정확성을 위해 currentWeatherView, currentWeatherModel, forecastWeatherModel로 수정해주세요.

Comment on lines +101 to +103
static func getImageUrl() -> URL? {
return URLComponents(string: "https://openweathermap.org/payload/api/media/file/10d@2x.png")?.url
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

이미지 URL이 하드코딩되어 있어 항상 같은 날씨 아이콘을 보여주는 버그가 있습니다. OpenWeatherMap API 응답에 포함된 icon ID를 사용하여 동적으로 URL을 생성해야 합니다. 예를 들어, https://openweathermap.org/img/wn/{icon_id}@2x.png 형식으로 URL을 만들어야 합니다.

Suggested change
static func getImageUrl() -> URL? {
return URLComponents(string: "https://openweathermap.org/payload/api/media/file/10d@2x.png")?.url
}
static func getImageUrl(iconId: String) -> URL? {
return URL(string: "https://openweathermap.org/img/wn/\(iconId)@2x.png")
}


// MARK: - Closures
/// 현재 날씨 UI 업데이트 요청 클로저
var UpdateCurrentUIClousure: (()-> Void)?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

클로저 프로퍼티 이름에 오타가 있고(Clousure), 네이밍 컨벤션에 맞지 않습니다. updateCurrentUIClosure로 수정하고, 일관성을 위해 UpdateForecastUIClosureupdateForecastUIClosure로 변경하는 것을 권장합니다.

Suggested change
var UpdateCurrentUIClousure: (()-> Void)?
var updateCurrentUIClosure: (()-> Void)?

Comment on lines +23 to +29
guard let decodeData = try? JSONDecoder().decode(T.self, from: data) else {
print("Decoding Failed")
completion(nil)
return
}
print("Decoding Success")
completion(decodeData)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

try?를 사용하여 디코딩 오류를 무시하면 디버깅이 어려워집니다. do-catch 블록을 사용하여 어떤 오류가 발생했는지 로그를 남기는 것이 좋습니다.

Suggested change
guard let decodeData = try? JSONDecoder().decode(T.self, from: data) else {
print("Decoding Failed")
completion(nil)
return
}
print("Decoding Success")
completion(decodeData)
do {
let decodeData = try JSONDecoder().decode(T.self, from: data)
print("Decoding Success")
completion(decodeData)
} catch {
print("Decoding Failed: \(error)")
completion(nil)
}


class OpenWeatherAPIService {
/// API 호출 메소드
func requestAPI<T: Decodable>(Url: URL, completion: @escaping (T?)-> Void) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Swift 네이밍 컨벤션에 따라 파라미터 이름은 소문자로 시작하는 lowerCamelCase를 사용해야 합니다. Urlurl로 변경해주세요.

Suggested change
func requestAPI<T: Decodable>(Url: URL, completion: @escaping (T?)-> Void) {
func requestAPI<T: Decodable>(url: URL, completion: @escaping (T?)-> Void) {

extension MainViewModel {

/// 현재 기상 정보 API 요청 메소드
func requestCurrentWheaterData() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

메소드 이름에 오타가 있습니다. requestCurrentWheaterDatarequestCurrentWeatherData로 수정해주세요.

    func requestCurrentWeatherData() {

}

/// 과거 기상 정보 API 요청 메소드
func requestForecastWheatherData() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

메소드 이름에 오타가 있습니다. requestForecastWheatherDatarequestForecastWeatherData로 수정해주세요.

    func requestForecastWeatherData() {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant