Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

날씨앱 [STEP 1] caron #36

Open
wants to merge 9 commits into
base: rft_2_caron
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions WeatherForecast/WeatherForecast.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
73B64D442BAB32DD0076ADE0 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73B64D432BAB32DD0076ADE0 /* Utils.swift */; };
C741F6702B58F00500A4DDC0 /* Weather.swift in Sources */ = {isa = PBXBuildFile; fileRef = C741F66F2B58F00500A4DDC0 /* Weather.swift */; };
C7743D8D2B21C38100DF0D09 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7743D8C2B21C38100DF0D09 /* AppDelegate.swift */; };
C7743D8F2B21C38100DF0D09 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7743D8E2B21C38100DF0D09 /* SceneDelegate.swift */; };
Expand All @@ -19,6 +20,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
73B64D432BAB32DD0076ADE0 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
C741F66F2B58F00500A4DDC0 /* Weather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weather.swift; sourceTree = "<group>"; };
C7743D892B21C38100DF0D09 /* WeatherForecast.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WeatherForecast.app; sourceTree = BUILT_PRODUCTS_DIR; };
C7743D8C2B21C38100DF0D09 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -68,6 +70,7 @@
C7743D902B21C38100DF0D09 /* ViewController.swift */,
C741F66F2B58F00500A4DDC0 /* Weather.swift */,
C7743DA22B21CA8500DF0D09 /* WeatherDetailViewController.swift */,
73B64D432BAB32DD0076ADE0 /* Utils.swift */,
C7743D922B21C38100DF0D09 /* Main.storyboard */,
C7743D952B21C38200DF0D09 /* Assets.xcassets */,
C7743D972B21C38200DF0D09 /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -150,6 +153,7 @@
C7743DA12B21C3B400DF0D09 /* WeatherTableViewCell.swift in Sources */,
C7743D912B21C38100DF0D09 /* ViewController.swift in Sources */,
C7743D8D2B21C38100DF0D09 /* AppDelegate.swift in Sources */,
73B64D442BAB32DD0076ADE0 /* Utils.swift in Sources */,
C7743DA32B21CA8600DF0D09 /* WeatherDetailViewController.swift in Sources */,
C741F6702B58F00500A4DDC0 /* Weather.swift in Sources */,
C7743D8F2B21C38100DF0D09 /* SceneDelegate.swift in Sources */,
Expand Down
28 changes: 28 additions & 0 deletions WeatherForecast/WeatherForecast/Utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Utils.swift
// WeatherForecast
//
// Created by qussk on 3/21/24.
//

import UIKit


class Utils {
static func dateSetUp(_ format: String?) -> DateFormatter {
Copy link

Choose a reason for hiding this comment

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

유틸성 기능을 별도의 타입과 메서드로 정의해보셨네요. 좋습니다!👍
지금처럼 다른 프로퍼티 없이 유틸리티 기능을 수행하는 부분에서는 static 메서드를 활용해도 좋아보입니다!

let formatter: DateFormatter = DateFormatter()
let dateFormat = DateFormat(dataFormater: format, dateFormatStyle: .none)
formatter.timeStyle = .short
formatter.locale = .init(identifier: dateFormat.locale)
formatter.dateFormat = dateFormat.dataFormater

guard format != nil else {
formatter.dateFormat = .none
return formatter
}

return formatter
}

}

96 changes: 61 additions & 35 deletions WeatherForecast/WeatherForecast/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@

import UIKit


class ViewController: UIViewController {

var tableView: UITableView!
let refreshControl: UIRefreshControl = UIRefreshControl()
var weatherJSON: WeatherJSON?
var icons: [UIImage]?
let imageChache: NSCache<NSString, UIImage> = NSCache()
let dateFormatter: DateFormatter = {
let formatter: DateFormatter = DateFormatter()
formatter.locale = .init(identifier: "ko_KR")
formatter.dateFormat = "yyyy-MM-dd(EEEEE) a HH:mm"
return formatter
}()

var tempUnit: TempUnit = .metric

Expand All @@ -27,15 +23,21 @@ class ViewController: UIViewController {
}
}

enum WeatherTitleType: String {
case celsius = "섭씨"
case fahrenheit = "화씨"
}
Copy link

Choose a reason for hiding this comment

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

온도 단위를 표현하는 타입으로 분리해보셨네요!👍


extension ViewController {

@objc private func changeTempUnit() {
switch tempUnit {
case .imperial:
tempUnit = .metric
navigationItem.rightBarButtonItem?.title = "섭씨"
navigationItem.rightBarButtonItem?.title = "\(WeatherTitleType.celsius.rawValue)"
case .metric:
tempUnit = .imperial
navigationItem.rightBarButtonItem?.title = "화씨"
navigationItem.rightBarButtonItem?.title = "\(WeatherTitleType.fahrenheit.rawValue)"
}
refresh()
}
Expand All @@ -47,7 +49,7 @@ extension ViewController {
}

private func initialSetUp() {
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "화씨", image: nil, target: self, action: #selector(changeTempUnit))
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "\(WeatherTitleType.fahrenheit)", image: nil, target: self, action: #selector(changeTempUnit))

layTable()

Expand Down Expand Up @@ -118,19 +120,57 @@ extension ViewController: UITableViewDataSource {
return cell
}

cell.weatherLabel.text = weatherForecastInfo.weather.main
cell.descriptionLabel.text = weatherForecastInfo.weather.description
cell.temperatureLabel.text = "\(weatherForecastInfo.main.temp)\(tempUnit.expression)"

let date: Date = Date(timeIntervalSince1970: weatherForecastInfo.dt)
cell.dateLabel.text = dateFormatter.string(from: date)

let iconName: String = weatherForecastInfo.weather.icon
let urlString: String = "https://openweathermap.org/img/wn/\(iconName)@2x.png"
cell.delegate = self

WeatherTableCell(cell: cell, indexPath: indexPath,iconName: weatherForecastInfo.weather.icon, imageView: cell.weatherIcon)

cell.configure(weatherIcon: cell.weatherIcon, dateLabel: dataTimeIntervalSince1970(weatherForecastInfo.dt), temperatureLabel: "\(weatherForecastInfo.main.temp)\(tempUnit.expression)", weatherLabel: weatherForecastInfo.weather.main, descriptionLabel: weatherForecastInfo.weather.description)

return cell
}
}

extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)

let detailViewController: WeatherDetailViewController = WeatherDetailViewController()
detailViewController.weatherForecastInfo = weatherJSON?.weatherForecast[indexPath.row]
detailViewController.cityInfo = weatherJSON?.city
detailViewController.tempUnit = tempUnit
navigationController?.show(detailViewController, sender: self)
}
}
extension ViewController : dateFomatterSetUp {
private func dataTimeIntervalSince1970(_ dt: TimeInterval) -> String {
let date: Date = Date(timeIntervalSince1970: dt)
return dateSetUp(DataCase.long).string(from: date)
}

func dateSetUp(_ format: String?) -> DateFormatter {
let formatter: DateFormatter = DateFormatter()
let dateFormat = DateFormat(dataFormater: format, dateFormatStyle: .none)
formatter.timeStyle = .short
formatter.locale = .init(identifier: dateFormat.locale)
formatter.dateFormat = dateFormat.dataFormater

guard format != nil else {
formatter.dateFormat = .none
return formatter
}

return formatter
}

}

extension ViewController: WeatherTableDelegate {
func WeatherTableCell(cell: WeatherTableViewCell, indexPath: IndexPath, iconName: String, imageView: UIImageView) {
Copy link

Choose a reason for hiding this comment

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

기존의 tableView(_:cellForRowAt:)에 작성되어 있던 로직을 새로운 메서드로 분리해보셨네요!
분리한 메서드에서도 다양한 일을 수행하는 것으로 보입니다. 각 역할을 파악해서 새로운 타입이나 메서드를 구현해보면 좋을 것 같습니다!

let urlString: String = "\(ImageURLType.path.rawValue)\(iconName)\(ImageURLType.png.rawValue)"

if let image = imageChache.object(forKey: urlString as NSString) {
cell.weatherIcon.image = image
return cell
return
}

Task {
Expand All @@ -141,26 +181,12 @@ extension ViewController: UITableViewDataSource {
}

imageChache.setObject(image, forKey: urlString as NSString)

if indexPath == tableView.indexPath(for: cell) {
cell.weatherIcon.image = image
}
}

return cell
}
}

extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)

let detailViewController: WeatherDetailViewController = WeatherDetailViewController()
detailViewController.weatherForecastInfo = weatherJSON?.weatherForecast[indexPath.row]
detailViewController.cityInfo = weatherJSON?.city
detailViewController.tempUnit = tempUnit
navigationController?.show(detailViewController, sender: self)
}

}


5 changes: 5 additions & 0 deletions WeatherForecast/WeatherForecast/Weather.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ enum TempUnit: String {
}
}

// MARK: - ImageURLType
enum ImageURLType: String {
case path = "https://openweathermap.org/img/wn/"
case png = "@2x.png"
}
Comment on lines +65 to +68
Copy link

Choose a reason for hiding this comment

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

URL String을 별도로 관리해보셨네요!👍

99 changes: 73 additions & 26 deletions WeatherForecast/WeatherForecast/WeatherDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,47 @@

import UIKit

protocol WeatherForecastInfoDelegate {
func weatherTask(iconName: String, imageView: UIImageView)
}
Copy link

Choose a reason for hiding this comment

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

WeatherForecastInfoDelegate 프로토콜을 구현하신 이유가 있을까요?


protocol dateFomatterSetUp {
func dateSetUp(_ format: String?) -> DateFormatter
}
Copy link

Choose a reason for hiding this comment

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

지금과 같은 경우라면 프로토콜까지 구현하지 않아도 될 것 같습니다.
프로토콜을 사용해서 해결할 수 있는 문제를 더 알아보면 좋을 것 같습니다!


struct DateFormat {
var dataFormater: String?
let locale = "ko_KR"
let dateFormatStyle: DateFormatter.Style

init(dataFormater: String?, dateFormatStyle: DateFormatter.Style) {
self.dataFormater = dataFormater
self.dateFormatStyle = dateFormatStyle
}
}

enum DetailGroupList: String {
case temperature = "현재 기온 : "
case feelsLike = "체감 기온 : "
case maximumTemperature = "최고 기온 : "
case minimumTemperature = "최저 기온 : "
case pop = "강수 확률 : "
case humidity = "습도 : "
case sunriseTime = "일출 : "
case sunsetTime = "일몰 : "
}

struct DataCase {
static let long = "yyyy-MM-dd(EEEEE) a HH:mm"

}

class WeatherDetailViewController: UIViewController {

var weatherForecastInfo: WeatherForecastInfo?
var cityInfo: City?
var tempUnit: TempUnit = .metric

let dateFormatter: DateFormatter = {
let formatter: DateFormatter = DateFormatter()
formatter.locale = .init(identifier: "ko_KR")
formatter.dateFormat = "yyyy-MM-dd(EEEEE) a HH:mm"
return formatter
}()


override func viewDidLoad() {
super.viewDidLoad()
initialSetUp()
Expand All @@ -30,7 +58,7 @@ class WeatherDetailViewController: UIViewController {
guard let listInfo = weatherForecastInfo else { return }

let date: Date = Date(timeIntervalSince1970: listInfo.dt)
navigationItem.title = dateFormatter.string(from: date)
navigationItem.title = Utils.dateSetUp(DataCase.long).string(from: date)

let iconImageView: UIImageView = UIImageView()
let weatherGroupLabel: UILabel = UILabel()
Expand Down Expand Up @@ -95,33 +123,52 @@ class WeatherDetailViewController: UIViewController {

weatherGroupLabel.text = listInfo.weather.main
weatherDescriptionLabel.text = listInfo.weather.description
temperatureLabel.text = "현재 기온 : \(listInfo.main.temp)\(tempUnit.expression)"
feelsLikeLabel.text = "체감 기온 : \(listInfo.main.feelsLike)\(tempUnit.expression)"
maximumTemperatureLable.text = "최고 기온 : \(listInfo.main.tempMax)\(tempUnit.expression)"
minimumTemperatureLable.text = "최저 기온 : \(listInfo.main.tempMin)\(tempUnit.expression)"
popLabel.text = "강수 확률 : \(listInfo.main.pop * 100)%"
humidityLabel.text = "습도 : \(listInfo.main.humidity)%"
temperatureLabel.text = "\(DetailGroupList.temperature) \(listInfo.main.temp)\(tempUnit.expression)"
feelsLikeLabel.text = "\(DetailGroupList.feelsLike) \(listInfo.main.feelsLike)\(tempUnit.expression)"
maximumTemperatureLable.text = "\(DetailGroupList.maximumTemperature)\(listInfo.main.tempMax)\(tempUnit.expression)"
minimumTemperatureLable.text = "\(DetailGroupList.minimumTemperature)\(listInfo.main.tempMin)\(tempUnit.expression)"
popLabel.text = "\(DetailGroupList.pop)\(listInfo.main.pop * 100)%"
humidityLabel.text = "\(DetailGroupList.humidity) \(listInfo.main.humidity)%"

if let cityInfo {
let formatter: DateFormatter = DateFormatter()
formatter.dateFormat = .none
formatter.timeStyle = .short
formatter.locale = .init(identifier: "ko_KR")
sunriseTimeLabel.text = "일출 : \(formatter.string(from: Date(timeIntervalSince1970: cityInfo.sunrise)))"
sunsetTimeLabel.text = "일몰 : \(formatter.string(from: Date(timeIntervalSince1970: cityInfo.sunset)))"
sunriseTimeLabel.text = "\(DetailGroupList.sunriseTime) \(Utils.dateSetUp(nil).string(from: Date(timeIntervalSince1970: cityInfo.sunrise)))"
sunsetTimeLabel.text = "\(DetailGroupList.sunsetTime) \(Utils.dateSetUp(nil).string(from: Date(timeIntervalSince1970: cityInfo.sunset)))"
}

Task {
let iconName: String = listInfo.weather.icon
let urlString: String = "https://openweathermap.org/img/wn/\(iconName)@2x.png"
weatherTask(iconName: listInfo.weather.icon, imageView: iconImageView)

}
}

extension WeatherDetailViewController : WeatherForecastInfoDelegate {
//이미지 처리
func weatherTask(iconName: String, imageView: UIImageView) {
Task {
let iconName: String = iconName
let urlString: String = "\(ImageURLType.path.rawValue)\(iconName)\(ImageURLType.png.rawValue)"
guard let url: URL = URL(string: urlString),
let (data, _) = try? await URLSession.shared.data(from: url),
let image: UIImage = UIImage(data: data) else {
return
}

iconImageView.image = image
imageView.image = image
}
}

// //날짜형식 변환
// func dateSetUp(_ format: String?) -> DateFormatter {
// let formatter: DateFormatter = DateFormatter()
// let dateFormat = DateFormat(dataFormater: format, dateFormatStyle: .none)
// formatter.timeStyle = .short
// formatter.locale = .init(identifier: dateFormat.locale)
// formatter.dateFormat = dateFormat.dataFormater
//
// guard format != nil else {
// formatter.dateFormat = .none
// return formatter
// }
//
// return formatter
// }
Copy link

Choose a reason for hiding this comment

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

불필요한 주석은 제거해보는 것이 어떨까요?


}
14 changes: 14 additions & 0 deletions WeatherForecast/WeatherForecast/WeatherTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@

import UIKit

protocol WeatherTableDelegate {
func WeatherTableCell(cell: WeatherTableViewCell, indexPath: IndexPath, iconName: String, imageView: UIImageView)
}
Copy link

Choose a reason for hiding this comment

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

WeatherTableDelegate 프로토콜을 구현하신 이유가 있을까요?


class WeatherTableViewCell: UITableViewCell {
var delegate: WeatherTableDelegate?
Copy link

Choose a reason for hiding this comment

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

지금의 선언 형태에서 delegate 프로퍼티에 클래스 구체 타입이 할당 되었을 때, 메모리 이슈가 발생할 수 있지 않을까요?
현재 타입 내에서 delegate 프로퍼티를 사용하는 부분이 안보입니다! delegate 패턴에 대해 더 확인해보면 좋을 것 같습니다!


var weatherIcon: UIImageView!
var dateLabel: UILabel!
var temperatureLabel: UILabel!
Expand Down Expand Up @@ -93,6 +99,14 @@ class WeatherTableViewCell: UITableViewCell {
])
}

final func configure(weatherIcon:UIImageView, dateLabel:String, temperatureLabel:String, weatherLabel:String, descriptionLabel:String){
self.weatherIcon = weatherIcon
self.dateLabel.text = dateLabel
self.temperatureLabel.text = temperatureLabel
self.weatherLabel.text = weatherLabel
self.descriptionLabel.text = descriptionLabel
}

private func reset() {
weatherIcon.image = UIImage(systemName: "arrow.down.circle.dotted")
dateLabel.text = "0000-00-00 00:00:00"
Expand Down