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] jaySong #41

Open
wants to merge 2 commits into
base: rft_3_jaysong
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions WeatherForecast/WeatherForecast.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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 */; };
C7743D912B21C38100DF0D09 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7743D902B21C38100DF0D09 /* ViewController.swift */; };
C7743D912B21C38100DF0D09 /* WeatherListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7743D902B21C38100DF0D09 /* WeatherListViewController.swift */; };
C7743D942B21C38100DF0D09 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7743D922B21C38100DF0D09 /* Main.storyboard */; };
C7743D962B21C38200DF0D09 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C7743D952B21C38200DF0D09 /* Assets.xcassets */; };
C7743D992B21C38200DF0D09 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7743D972B21C38200DF0D09 /* LaunchScreen.storyboard */; };
Expand All @@ -23,7 +23,7 @@
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>"; };
C7743D8E2B21C38100DF0D09 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
C7743D902B21C38100DF0D09 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
C7743D902B21C38100DF0D09 /* WeatherListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherListViewController.swift; sourceTree = "<group>"; };
C7743D932B21C38100DF0D09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
C7743D952B21C38200DF0D09 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C7743D982B21C38200DF0D09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
Expand Down Expand Up @@ -65,7 +65,7 @@
C7743D8C2B21C38100DF0D09 /* AppDelegate.swift */,
C7743D8E2B21C38100DF0D09 /* SceneDelegate.swift */,
C7743DA02B21C3B400DF0D09 /* WeatherTableViewCell.swift */,
C7743D902B21C38100DF0D09 /* ViewController.swift */,
C7743D902B21C38100DF0D09 /* WeatherListViewController.swift */,
C741F66F2B58F00500A4DDC0 /* Weather.swift */,
C7743DA22B21CA8500DF0D09 /* WeatherDetailViewController.swift */,
C7743D922B21C38100DF0D09 /* Main.storyboard */,
Expand Down Expand Up @@ -148,7 +148,7 @@
buildActionMask = 2147483647;
files = (
C7743DA12B21C3B400DF0D09 /* WeatherTableViewCell.swift in Sources */,
C7743D912B21C38100DF0D09 /* ViewController.swift in Sources */,
C7743D912B21C38100DF0D09 /* WeatherListViewController.swift in Sources */,
C7743D8D2B21C38100DF0D09 /* AppDelegate.swift in Sources */,
C7743DA32B21CA8600DF0D09 /* WeatherDetailViewController.swift in Sources */,
C741F6702B58F00500A4DDC0 /* Weather.swift in Sources */,
Expand Down
8 changes: 4 additions & 4 deletions WeatherForecast/WeatherForecast/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wYg-u6-9nF">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wYg-u6-9nF">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<!--Weather List View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="WeatherForecast" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="WeatherListViewController" customModule="WeatherForecast" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
Expand Down
28 changes: 22 additions & 6 deletions WeatherForecast/WeatherForecast/Weather.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,29 @@ class Coord: Decodable {
}

// MARK: - Temperature Unit
enum TempUnit: String {
enum TempUnit: String, CaseIterable {
case metric, imperial
var expression: String {
switch self {
case .metric: return "℃"
case .imperial: return "℉"
}
guard let expression = expressionMapping[self] else { return ""}
return expression
}
Comment on lines 55 to +58
Copy link

Choose a reason for hiding this comment

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

섭씨와 화씨 전환에 따른 온도 수치 변화까지 적용해보면 좋을 것 같습니다!


var desc: String {
guard let desc = descMapping[self] else { return ""}
return desc
}

private var expressionMapping: [TempUnit: String] {
return [
TempUnit.metric: "℃",
TempUnit.imperial: "℉"
]
}

private var descMapping: [TempUnit: String] {
return [
TempUnit.metric: "섭씨",
TempUnit.imperial: "화씨"
]
}
}

116 changes: 60 additions & 56 deletions WeatherForecast/WeatherForecast/WeatherDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ import UIKit

class WeatherDetailViewController: UIViewController {

private let iconImageView: UIImageView = UIImageView()
private let weatherGroupLabel: UILabel = UILabel()
private let weatherDescriptionLabel: UILabel = UILabel()
private let temperatureLabel: UILabel = UILabel()
private let feelsLikeLabel: UILabel = UILabel()
private let maximumTemperatureLable: UILabel = UILabel()
private let minimumTemperatureLable: UILabel = UILabel()
private let popLabel: UILabel = UILabel()
private let humidityLabel: UILabel = UILabel()
private let sunriseTimeLabel: UILabel = UILabel()
private let sunsetTimeLabel: UILabel = UILabel()
private let spacingView: UIView = UIView()
private var mainStackView: UIStackView?

var weatherForecastInfo: WeatherForecastInfo?
var cityInfo: City?
var tempUnit: TempUnit = .metric
Comment on lines 25 to 27
Copy link

Choose a reason for hiding this comment

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

외부에서 직접 접근해서 데이터를 받을 수도 있지만, 직접 접근이 아닌 방식으로 데이터를 초기화할 수 있도록 해보면 좋을 것 같습니다! DI와 같은 키워드를 확인해보면 좋을 것 같습니다!


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

override func viewDidLoad() {
super.viewDidLoad()
Expand All @@ -26,28 +34,22 @@ class WeatherDetailViewController: UIViewController {

private func initialSetUp() {
view.backgroundColor = .white

// 옵셔널 언래핑을 해서 파라미터로 전달하는게 나을지, 아니면 각 메서드 안에서 하는게 나을지
guard let listInfo = weatherForecastInfo else { return }
Comment on lines +37 to 38
Copy link

Choose a reason for hiding this comment

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

언래핑 시점이 언제 적당할 지 고민해보면 좋을 것 같습니다! 그리고 어떤 상황에서 guard문을 사용할지, if let문을 사용할지 부분도 생각해보면 좋을 것 같습니다!
두 문법 다 언래핑을 지원하지만 guard문의 경우 언래핑 이전에 조기 종료 역할을 가지고 있어서 상황에 맞는 방식을 적용하면 될 것 같습니다!


let date: Date = Date(timeIntervalSince1970: listInfo.dt)
setTitle(listInfo.dt)
setMainStackView()
setSubviewData(listInfo)
setCityInfo()
}

private func setTitle(_ dt: TimeInterval) {
let date: Date = Date(timeIntervalSince1970: dt)
navigationItem.title = dateFormatter.string(from: date)

let iconImageView: UIImageView = UIImageView()
let weatherGroupLabel: UILabel = UILabel()
let weatherDescriptionLabel: UILabel = UILabel()
let temperatureLabel: UILabel = UILabel()
let feelsLikeLabel: UILabel = UILabel()
let maximumTemperatureLable: UILabel = UILabel()
let minimumTemperatureLable: UILabel = UILabel()
let popLabel: UILabel = UILabel()
let humidityLabel: UILabel = UILabel()
let sunriseTimeLabel: UILabel = UILabel()
let sunsetTimeLabel: UILabel = UILabel()
let spacingView: UIView = UIView()
spacingView.backgroundColor = .clear
spacingView.setContentHuggingPriority(.defaultLow, for: .vertical)

let mainStackView: UIStackView = .init(arrangedSubviews: [
}

private func setMainStackView() {
mainStackView = .init(arrangedSubviews: [
iconImageView,
weatherGroupLabel,
weatherDescriptionLabel,
Expand All @@ -61,7 +63,26 @@ class WeatherDetailViewController: UIViewController {
sunsetTimeLabel,
spacingView
])


setUISubviews()
layMainStackView()
}

private func setSubviewData(_ listInfo: WeatherForecastInfo) {
weatherGroupLabel.text = listInfo.weather.main
weatherDescriptionLabel.text = listInfo.weather.description
temperatureLabel.text = "현재 기온 : \(listInfo.main.temp.changeTemperature(by:tempUnit))\(tempUnit.expression)"
feelsLikeLabel.text = "체감 기온 : \(listInfo.main.feelsLike)\(tempUnit.expression)"
maximumTemperatureLable.text = "최고 기온 : \(listInfo.main.tempMax.changeTemperature(by:tempUnit))\(tempUnit.expression)"
minimumTemperatureLable.text = "최저 기온 : \(listInfo.main.tempMin.changeTemperature(by:tempUnit))\(tempUnit.expression)"
popLabel.text = "강수 확률 : \(listInfo.main.pop * 100)%"
humidityLabel.text = "습도 : \(listInfo.main.humidity)%"
iconImageView.setImage(from: listInfo.weather.icon)
}

private func setUISubviews() {
guard let mainStackView = mainStackView else { return }

mainStackView.arrangedSubviews.forEach { subview in
guard let subview: UILabel = subview as? UILabel else { return }
subview.textColor = .black
Expand All @@ -73,7 +94,12 @@ class WeatherDetailViewController: UIViewController {

weatherGroupLabel.font = .preferredFont(forTextStyle: .largeTitle)
weatherDescriptionLabel.font = .preferredFont(forTextStyle: .largeTitle)

spacingView.backgroundColor = .clear
spacingView.setContentHuggingPriority(.defaultLow, for: .vertical)
}

private func layMainStackView() {
guard let mainStackView = mainStackView else { return }
mainStackView.axis = .vertical
mainStackView.alignment = .center
mainStackView.spacing = 8
Expand All @@ -92,36 +118,14 @@ class WeatherDetailViewController: UIViewController {
iconImageView.widthAnchor.constraint(equalTo: safeArea.widthAnchor,
multiplier: 0.3)
])

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)%"

}

private func setCityInfo() {
if let cityInfo {
let formatter: DateFormatter = DateFormatter()
formatter.dateFormat = .none
let formatter: DateFormatter = DateFormatter(format: .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)))"
}

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

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
sunriseTimeLabel.text = "일출 : \(formatter.string(from: cityInfo.sunrise))"
sunsetTimeLabel.text = "일몰 : \(formatter.string(from: cityInfo.sunset))"
}
}
}
Loading