-
Notifications
You must be signed in to change notification settings - Fork 26
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
base: rft_2_caron
Are you sure you want to change the base?
Changes from 5 commits
5ed0660
76ee638
003b688
73d930b
a4b508f
91bbd09
def2e10
a5e2e31
3170a6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 { | ||
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 | ||
} | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
||
|
@@ -27,15 +23,21 @@ class ViewController: UIViewController { | |
} | ||
} | ||
|
||
enum WeatherTitleType: String { | ||
case celsius = "섭씨" | ||
case fahrenheit = "화씨" | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
} | ||
|
@@ -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() | ||
|
||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기존의 |
||
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 { | ||
|
@@ -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) | ||
} | ||
|
||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. URL String을 별도로 관리해보셨네요!👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,19 +6,47 @@ | |
|
||
import UIKit | ||
|
||
protocol WeatherForecastInfoDelegate { | ||
func weatherTask(iconName: String, imageView: UIImageView) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
protocol dateFomatterSetUp { | ||
func dateSetUp(_ format: String?) -> DateFormatter | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
|
@@ -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() | ||
|
@@ -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 | ||
// } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 불필요한 주석은 제거해보는 것이 어떨까요? |
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,13 @@ | |
|
||
import UIKit | ||
|
||
protocol WeatherTableDelegate { | ||
func WeatherTableCell(cell: WeatherTableViewCell, indexPath: IndexPath, iconName: String, imageView: UIImageView) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
class WeatherTableViewCell: UITableViewCell { | ||
var delegate: WeatherTableDelegate? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지금의 선언 형태에서 |
||
|
||
var weatherIcon: UIImageView! | ||
var dateLabel: UILabel! | ||
var temperatureLabel: UILabel! | ||
|
@@ -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" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유틸성 기능을 별도의 타입과 메서드로 정의해보셨네요. 좋습니다!👍
지금처럼 다른 프로퍼티 없이 유틸리티 기능을 수행하는 부분에서는
static
메서드를 활용해도 좋아보입니다!