# ์ผ๊ธฐ์ฅ README
# ๐ ์ผ๊ธฐ์ฅ
> ๋์ ์ผ๊ธฐ๋ฅผ ๋ฑ๋ก, ์์ , ์ญ์ ํ ์ ์๋ ์ฑ
>
> ํ๋ก์ ํธ ๊ธฐ๊ฐ: 2023.04.24-2023.05.12
>
## ํ์
| kokkilE | ํ๋ชจ๋ฆฌ |
| :---:|:---:|
| <Img src ="https://i.imgur.com/4I8bNFT.png" width="200" height="200"/> |<Img src ="https://i.imgur.com/VJtnO5j.png" width="200" height="200"/>
| [Github Profile](https://github.com/kokkilE) |[Github Profile](https://github.com/hyemory)
## ๋ชฉ์ฐจ
1. [ํ์๋ผ์ธ](#ํ์๋ผ์ธ)
2. [ํ๋ก์ ํธ ๊ตฌ์กฐ](#ํ๋ก์ ํธ-๊ตฌ์กฐ)
3. [์คํ ํ๋ฉด](#์คํ-ํ๋ฉด)
4. [ํธ๋ฌ๋ธ ์ํ
](#ํธ๋ฌ๋ธ-์ํ
)
5. [์ฐธ๊ณ ๋งํฌ](#์ฐธ๊ณ -๋งํฌ)
6. [ํ ํ๊ณ ](#ํ-ํ๊ณ )
# ํ์๋ผ์ธ
|๋ ์ง|๋ด์ฉ|
|:-----:| ------ |
| 2023.04.24 | - JSON Decode ๋ชจ๋ธ์ธ Contents ํ์
๊ตฌํ <br>- ์ผ๊ธฐ ๋ฆฌ์คํธ ํ๋ฉด ๊ตฌํ <br> - custom TableviewCell ๊ตฌํ <br>- SwiftLint ์ ์ฉ|
| 2023.04.25 | - ๋ ์ง ์ง์ญํ ๊ตฌํ <br>- ์์ธํ์ด์ง ํ๋ฉด ๊ตฌํ <br> - KeyBoard์ ๋ฐ๋ฅธ ๋ทฐ ์์น ๋ณ๊ฒฝ ๊ตฌํ|
| 2023.04.26 | - DecodeManager ๊ตฌํ<br>- AlertManager ๊ตฌํ <br>- keyboardLayoutGuide ์ ์ฉ <br>- ํ๋ก์ ํธ Minimum DeployMents ๋ณ๊ฒฝ (14.0 โ 15.0) |
| 2023.04.28 | - CoreDataManager - Create, Read ๊ธฐ๋ฅ ๊ตฌํ<br>- Coredata์ Entity ๊ตฌํ |
| 2023.05.01 | - Core Data Update, Delete ๊ตฌํ์ ์ํ ์ถ๊ฐ ํ์ต |
| 2023.05.02 | - CoreDataManager - Update, Delete ๊ธฐ๋ฅ ๊ตฌํ<br>- VC์ ๋ฐ์ดํฐ CRUD ๊ธฐ๋ฅ ๊ตฌํ |
| 2023.05.03 | - ์๋ฌ Alert ๊ธฐ๋ฅ ๊ตฌํ <br> - ๋ฐ์ดํฐ๊ฐ ํธ์ง๋ ๋ ์ ์ฒด ๋ฐ์ดํฐ๊ฐ ์๋ ํธ์ง๋ ๋ฐ์ดํฐ๋ง reload ํ๋๋ก ๊ธฐ๋ฅ ์์ |
| 2023.05.04 | - ์๋ฌ ์ฒ๋ฆฌ ์์น ์์ (model โ VC)|
| 2023.05.05 | - ํ๋ก์ ํธ ํ๊ณ ๋ฐ ํด์ |
| 2023.05.08 | - NetworkManager, EndPoint ๊ตฌํ |
| 2023.05.09 | - Core Location์ผ๋ก ์ฌ์ฉ์ ์์น์ ๋ณด ์ ์ฅ ๊ตฌํ |
| 2023.05.10 | - ํ๋ฉด์ ๋ ์จ ์์ด์ฝ์ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ ๊ตฌํ |
| 2023.05.11 | - ์ฝ๋ ์ ์ฒด ๋ฆฌํฉํ ๋ง (ํ์
๋ถ๋ฆฌ, ์ปจ๋ฒค์
์ ๋ฆฌ) |
| 2023.05.12 | - ํ๋ก์ ํธ ํ๊ณ |
<br/>
# ํ๋ก์ ํธ ๊ตฌ์กฐ
## Class Diagram
<details>
<summary> ํด๋์ค ๋ค์ด์ด๊ทธ๋จ ๋ณด๊ธฐ (ํด๋ฆญ) </summary>
<div markdown="1">

</div>
</details>
## File Tree
<details>
<summary> ํ์ผ ํธ๋ฆฌ ๋ณด๊ธฐ (ํด๋ฆญ) </summary>
<div markdown="1">
```typescript!
โโโ .swiftlint.yml
โโโ Common
โ โโโ CoreData
โ โ โโโ Diary.xcdatamodeld
โ โ โ โโโ Diary v2.xcdatamodel
โ โ โ โโโ Diary.xcdatamodel
โ โ โโโ ContentsEntity+CoreDataClass.swift
โ โ โโโ ContentsEntity+CoreDataProperties.swift
โ โ โโโ CoreDataManager.swift
โ โโโ Extension
โ โ โโโ Date+.swift
โ โ โโโ NotificationName+.swift
โ โโโ Network
โ โ โโโ EndPoint.swift
โ โ โโโ NetworkManager.swift
โ โโโ Error
โ โ โโโ DiaryError.swift
โ โ โโโ NetworkError.swift
โ โโโ Utility
โ โ โโโ AlertManager.swift
โ โ โโโ DecodeManager.swift
โ โ โโโ LocationManager.swift
โ โโโ Model
โ โโโ ContentsDTO.swift
โ โโโ WeatherDTO.swift
โ โโโ Coordinate.swift
โโโ Presentation
โ โโโ DiaryList
โ โ โโโ Protocol
โ โ โ โโโ DiaryDetailViewControllerDelegate.swift
โ โ โ โโโ IdentifierType.swift
โ โ โโโ ContentsTableViewCell.swift
โ โ โโโ DiaryListViewController.swift
โ โโโ DiaryDetail
โ โโโ DiaryDetailViewController.swift
โ โโโ WeatherNetworkManager.swift
โโโ Resources
โ โโโ Info.plist
โโโ Application
โโโ AppDelegate.swift
โโโ SceneDelegate.swift
```
</div>
</details>
# ์คํ ํ๋ฉด
|<center>์ด๊ธฐ ํ๋ฉด<br>์ผ๊ธฐ ๋ชฉ๋ก ํ๋ฉด</center>|<center>๋ฐ์ดํฐ ๋ก๋ ์คํจ ์<br>์๋ฆผ ํ์</center>|<center>์ผ๊ธฐ ๋ชฉ๋ก ํ๋ฉด<br>์ค์์ดํ๋ก ๊ณต์ ๋ฐ ์ญ์ </center>|
|--| -- | -- |
|<img src="https://hackmd.io/_uploads/H1CTDXj42.gif" width=250> | <img src="https://i.imgur.com/kWbnD8y.gif" width=250> | <img src="https://hackmd.io/_uploads/SJn-uXiNn.gif" width=250> |
|<center>์ผ๊ธฐ ์์ธ ํ๋ฉด<br>์๋ก์ด ๋ฐ์ดํฐ ์ ์ฅ</center> |<center>์ผ๊ธฐ ์์ธ ํ๋ฉด<br>๋ฐ์ดํฐ ํธ์ง ํ ์ ์ฅ</center>|<center>์ผ๊ธฐ ์์ธ ํ๋ฉด<br>๋๋ณด๊ธฐ โ ๊ณต์ ๋ฐ ์ญ์ </center> |
| -- | -- | -- |
|<img src="https://hackmd.io/_uploads/SJhKuXjE2.gif" width=250> | <img src="https://hackmd.io/_uploads/HkST_7sVn.gif" width=250> | <img src="https://hackmd.io/_uploads/Hy9wYQoNn.gif" width=250> |
# ํธ๋ฌ๋ธ ์ํ
## 1๏ธโฃ ํค๋ณด๋๊ฐ ํธ์ง์ค์ธ ํ
์คํธ๋ฅผ ๊ฐ๋ฆฌ์ง ์๋๋ก ์ฒ๋ฆฌ
ํค๋ณด๋๊ฐ ๋ํ๋ ๋ ํธ์ง์ค์ธ ํ
์คํธ๋ฅผ ๊ฐ๋ฆฌ์ง ์๋๋ก ํ๊ธฐ ์ํด ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฐพ์ ๊ณ ๋ คํ์์ต๋๋ค.
- ํค๋ณด๋๊ฐ ๋ํ๋ ๋ textView์ ์คํ ๋ ์ด์์์ ์กฐ์ ํ์ฌ ๊ตฌํ
- ํค๋ณด๋๊ฐ ๋ํ๋ ๋ textView.contentInset์ ์กฐ์ ํ์ฌ ๊ตฌํ
- **keyboardLayoutGuide์ ์ ์ฝ์ผ๋ก ๊ตฌํ**
์์ ์ฒซ ๋ฒ์งธ, ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ Notification์ ํ์ฉํ์ฌ ํค๋ณด๋ ์ด๋ฒคํธ๋ฅผ ์์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํ์ด ๊ฐ๋ฅํ์ต๋๋ค.
๋ค๋ง ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ธ ์คํ ๋ ์ด์์์ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ ๊ฒฝ์ฐ, ๋ค์๊ณผ ๊ฐ์ด ๋๋ ์ด ์๊ฐ๋์ ํค๋ณด๋๊ฐ ๋ด๋ ค๊ฐ์๋ ์ฑ์์ง์ง ์๋ ๋ ์ด์์์ด ์ด์ํ๊ฒ ๋๊ปด์ก์ต๋๋ค.
<br/>
<img src= "https://i.imgur.com/L3u84Y7.gif" width=250>
<br/>
๋ ๋ฒ์งธ ๋ฐฉ๋ฒ๊ณผ ์ธ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋์์์ ๋ฌธ์ ๋ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค. ์ธ ๋ฒ์งธ ๋ฐฉ๋ฒ์ keyboardLayoutGuide์ ์ ์ฝ์กฐ๊ฑด์ผ๋ก ๋น๊ต์ ๊ฐ๋จํ ๊ตฌํ์ด ๊ฐ๋ฅํด ์ธ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ฑํํ์์ต๋๋ค.
๋ค๋ง keyboardLayoutGuide์ ์ฌ์ฉํ๊ธฐ ์ํด Minimum Deployments๋ฅผ iOS 15.0์ผ๋ก ์ฌ๋ ค์ผ ํ์ต๋๋ค.
### ๐ ์ฝ๋ ์ฐธ์กฐ
#### ํค๋ณด๋๊ฐ ๋ํ๋ ๋ textView์ ์คํ ๋ ์ด์์์ ์กฐ์ ํ์ฌ ๊ตฌํ
``` swift
@objc func keyboardWillShow(notification: Notification) {
guard let userInfo = notification.userInfo,
let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardHeight = keyboardFrameValue.cgRectValue.height
textViewBottomAnchor.isActive = false
// ํค๋ณด๋๊ฐ ๋ํ๋ ๊ฒฝ์ฐ textView์ bottomAnchor ์กฐ์
textViewBottomAnchor = textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -keyboardHeight)
textViewBottomAnchor.isActive = true
}
```
#### ํค๋ณด๋๊ฐ ๋ํ๋ ๋ textView.contentInset์ ์กฐ์ ํ์ฌ ๊ตฌํ
``` swift
@objc private func keyboardWillShow(notification: Notification) {
guard let userInfo = notification.userInfo,
let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardHeight = keyboardFrameValue.cgRectValue.height
textView.contentInset.bottom = keyboardHeight
textView.verticalScrollIndicatorInsets.bottom = keyboardHeight
}
```
#### โ
keyboardLayoutGuide์ ์ ์ฝ์ผ๋ก ๊ตฌํ
``` swift
private func configureLayout() {
//...
view.keyboardLayoutGuide.followsUndockedKeyboard = true
NSLayoutConstraint.activate([
view.keyboardLayoutGuide.topAnchor.constraint(equalTo: textView.bottomAnchor),
//...
textView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor)
])
}
```
## 2๏ธโฃ ์ผ๊ธฐ์ฅ ๋ด์ฉ์ด ์ ๋ถ ๋ณด์ด๋๋ก ์์
### ๐ ๋ฌธ์ ์
๊ฐ์ฅ ๊ธด ๊ธ์ ์์ ํ์ด์ง๋ก ์ด๋ํ์ ๋ ์๋ก ์คํฌ๋กคํ์ง ์์ผ๋ฉด ์ ๋ชฉ ๋ถ๋ถ์ด ์๋ ค๋ณด์ด๋ ํ์์ด ํ์ธ๋์ต๋๋ค.
<img src= "https://i.imgur.com/6GIrrZx.gif" width=250>
### โ๏ธ ํด๊ฒฐ๋ฐฉ์
`contentSize`๊ฐ ํ
์คํธ ๋ด์ฉ๋ณด๋ค ์์ ๋ฐ์ํ ํ์์ผ๋ก,
ํ์ด์ด๋ผํค๋ฅผ ์ค์ ํ ๋ ๋ทฐ์ offset์ ํฌ๊ธฐ๋ฅผ ์ด๊ธฐํ์์ผ์ฃผ๋ ์ ์์ ์ผ๋ก ํ์๋์์ต๋๋ค.
``` swift
private func configureLayout() {
view.addSubview(textView)
textView.contentOffset = .zero // ์ถ๊ฐ
// ์ดํ layout ์ค์
}
```
## 3๏ธโฃ ์์ธ ์ฒ๋ฆฌ ์ ๋ฆฌ
### ๐ ๋ฌธ์ ์
๊ธฐ๋ฅ ๊ตฌํ ์ค ์คํ
์๊ตฌ์ฌํญ ์ธ์ ์ด์ํ๋ค๊ณ ์๊ฐ๋๋ ๋ก์ง์ด ์ฌ๋ฌ๊ฐ์ง ์์์ต๋๋ค.
์ด ๋ด์ฉ๋ค์ ์์ธ์ ์ผ๋ก ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค๊ณ ์๊ฐํ์ฌ ๊ด๋ จ ์ ์ฑ
์ ์์ฒด์ ์ผ๋ก ํ์ํ์ฌ ๊ฒฐ์ ํ์ต๋๋ค.
### โ๏ธ ๊ฒฐ๊ณผ
1. ์ ๊ธ์ createํ ๋ ์๋ฌด ๋ด์ฉ๋ ์
๋ ฅํ์ง ์์ ๊ฒฝ์ฐ
โ ์ ์ฅ๋์ง ์์ต๋๋ค.
3. ์ ๊ธ์ createํ๊ณ + ์๋ ์ ์ฅ๋ ํ ๊ธ ๋ด์ฉ์ ์ ๋ถ ์ญ์ ํ ๊ฒฝ์ฐ
โ ๋น์ด์๋ ๋ด์ฉ์ด ์ ์ฅ๋ฉ๋๋ค.
5. ๊ธ์ ํ ์ค๋ง ๋ฑ๋กํ ๊ฒฝ์ฐ (title๋ง)
โ title์ ์
๋ ฅํ ๋ด์ฉ์ด ์ ์ฅ๋๊ณ body๋ ๋น ๋ฌธ์์ด๋ก ์ ์ฅ๋ฉ๋๋ค.
7. ์ด๋ฏธ ๋ฑ๋ก๋ ๊ธ์ ๋ด์ฉ์ ์ ๋ถ ์ง์ด ๊ฒฝ์ฐ update ์ฌ๋ถ
โ ๋น์ด์๋ ๋ด์ฉ์ด ์ ์ฅ๋ฉ๋๋ค.
9. ์ ๊ธ์ createํ ๋ ๋๋ณด๊ธฐ ๋ฒํผ(right bar button) ๋
ธ์ถ ์ฌ๋ถ
โ ์
๋ ฅ ํ ๋ด์ฉ์ ๋ฐ๋ก ๊ณต์ ํ๊ฑฐ๋, ์๋์ ์ฅ๋ ๋ด์ฉ์ ๋ฐ๋ก ์ญ์ ์ํฌ ์ ์๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ์ ๊ธ์ ์ ์ฅํ ๋๋ ๋ฒํผ์ด ๋
ธ์ถ๋ฉ๋๋ค.
## 4๏ธโฃ ๋ชฉ๋ก ํ๋ฉด๊ณผ ์์ธ ํ๋ฉด๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ
์์ธ ํ๋ฉด์์ ํธ์ง๋ ๋ฐ์ดํฐ๋ฅผ ๋ชฉ๋ก ํ๋ฉด์๋ ๋ฐ์ํ๊ธฐ ์ํ ๋ก์ง์ ๊ตฌํํ์์ต๋๋ค.
๊ฐ์ ์ ์๋ ๋ชฉ๋ก ํ๋ฉด์ผ๋ก ๋์์ฌ ๋ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์ฝ๊ณ , ๋ชฉ๋ก์ reloadํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ์์ต๋๋ค.
๊ฐ์ ํ์๋ ํธ์ง๋ ๋ฐ์ดํฐ๋ง ๊ฐฑ์ ๋๋๋ก ๊ตฌํํ์์ต๋๋ค.
### ๐ ๋ฌธ์ ์
์์ธ ํ๋ฉด์์ ๋ฐ์ดํฐ๊ฐ ํธ์ง๋ ํ ๋ค์ ๋ชฉ๋ก ํ๋ฉด์ผ๋ก ๋์์ฌ ๋, ํธ์ง๋ ๋ฐ์ดํฐ๋ฅผ ๋ชฉ๋ก ํ๋ฉด์ ๋ฐ์ํ๊ธฐ ์ํด `DiaryDetailViewController`์์๋ ๋ฐ์ดํฐ๊ฐ ํธ์ง๋ ๋ CoreData ์ ์ฅ์์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํด์ฃผ์์ต๋๋ค. ์ดํ ๋ชฉ๋ก ํ๋ฉด์ด ๋ค์ ๋ํ๋ ๋ ์๋์ ๊ฐ์ ์ฝ๋๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํ์์ต๋๋ค.
**DiaryListViewController**
``` swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchContents()
tableView.reloadData()
}
```
์ ์ฝ๋๋ ๋์์ ๋ฌธ์ ๋ ์์์ง๋ง, ํ๋์ ๋ฐ์ดํฐ๋ง ํธ์ง๋๋ ์ํฉ์์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์ฝ์ด์ค๊ณ , reloadํ๊ธฐ ๋๋ฌธ์ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ฐ์ดํฐ๊ฐ ๋ง์์ง์๋ก ์ค๋ฒํค๋๋ ์ปค์ง๊ธฐ ๋๋ฌธ์ ๊ฐ์ ํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํ์์ต๋๋ค.
### โ๏ธ ํด๊ฒฐ๋ฐฉ์
์์ธ ํ๋ฉด์์ ํธ์ง๋ ๋ฐ์ดํฐ๋ง ๋ชฉ๋ก ํ๋ฉด์์ ๊ฐฑ์ ํ ์ ์๋๋ก delegate ํจํด์ ์ ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ๊ฐ์ ํ์์ต๋๋ค.
**DiaryListViewController**
``` swift
// MARK: - DiaryDetailViewController Delegate
extension DiaryListViewController: DiaryDetailViewControllerDelegate {
func createCell(contents: Contents) {
// ...
contentsList?.append(contents)
tableView.insertRows(at: [selectedCellIndex], with: .automatic)
}
func updateCell(contents: Contents) {
// ...
contentsList?[selectedCellIndex.row] = contents
tableView.reloadRows(at: [selectedCellIndex], with: .automatic)
}
func deleteCell() {
// ...
contentsList?.remove(at: selectedCellIndex.row)
tableView.deleteRows(at: [selectedCellIndex], with: .fade)
}
}
```
**DiaryDetailViewController**
``` swift
// ...
weak var delegate: DiaryDetailViewControllerDelegate?
// ...
private func updateContents() {
// ...
delegate?.updateCell(contents: contents)
// ...
}
private func createContents() {
// ...
delegate?.createCell(contents: contents)
// ...
}
private func deleteContents() {
// ...
delegate?.deleteCell()
// ...
}
```
## 5๏ธโฃ ๋ ์จ ํ์ ๊ธฐ๋ฅ ๊ตฌํ ์ ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด์กดํ๊ธฐ ์ํ ์ฒ๋ฆฌ
### ๐ ๋ฌธ์ ์
๋ ์จ ์ ๋ณด๋ฅผ ํ์ํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ฉด์ Core Data์ Entity ๋ชจ๋ธ์ด ๋ณ๊ฒฝ๋์์ต๋๋ค.
### โ๏ธ ํด๊ฒฐ๋ฐฉ์
๊ทธ์ ๋ฐ๋ผ ๊ธฐ์กด์ Core Data์ ์ ์ฅ๋์ด์๋ ๋ชจ๋ธ๊ณผ Migrationํ์์ต๋๋ค.
์ด ๊ณผ์ ์์ ๊ธฐ์กด์ ๋ ์จ ์ ๋ณด๊ฐ ์๋ ๋ฐ์ดํฐ๋ ๋ ์จ ์ ๋ณด๊ฐ ์๋ ์ฑ๋ก ๋ฐ์์ค๊ธฐ ์ํด, `ContentsDTO`์ ๋ค์๊ณผ ๊ฐ์ด `weather`๋ฅผ ์ต์
๋๋ก ๊ตฌํํ์์ต๋๋ค.
``` swift
/* ContentsDTO์ ๋ค์์ ์ฉ๋๋ก ์ฌ์ฉ๋ฉ๋๋ค.
1. JSON ๋ฐ์ดํฐ Decode๋ฅผ ์ํ ๋ชจ๋ธ
2. VC์์ ์ฌ์ฉ๋๋ ๋ชจ๋ธ
3. VC์์ CoreData์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๋ชจ๋ธ */
struct ContentsDTO: Codable {
var title: String
var body: String
let date: Double
let identifier: UUID?
var weather: Weather?
...
}
```
๋ ์ง ์ ๋ณด๊ฐ ์์ผ๋ฉด ์๋ ๋๋ก, ์์ผ๋ฉด ์๋ ๋๋ก ์ฑ์ ํ์๋ฉ๋๋ค.
# ์ฐธ๊ณ ๋งํฌ
## ๋ธ๋ก๊ทธ
- [WWDC 21 ๋ถ์: Adjust Your Layout with Keyboard Layout Guide](https://zeddios.tistory.com/1282)
- [iOS) CoreData - Migration](https://yeonduing.tistory.com/48)
- [IOS SWIFT ํ์ฌ์์น ๊ตฌํ๊ธฐ (CoreLocation, CLLocationManager)](https://tom7930.tistory.com/28)
## ๊ณต์ ๋ฌธ์
- [UITextView](https://developer.apple.com/documentation/uikit/uitextview)
- [DateFormatter](https://developer.apple.com/documentation/foundation/dateformatter)
- [preferredLanguages](https://developer.apple.com/documentation/foundation/nslocale/1415614-preferredlanguages)
- [Adjusting Your Layout with Keyboard Layout Guide](https://developer.apple.com/documentation/uikit/keyboards_and_input/adjusting_your_layout_with_keyboard_layout_guide)
- [keyboardLayoutGuide](https://developer.apple.com/documentation/uikit/uiview/3752221-keyboardlayoutguide)
- [followsUndockedKeyboard](https://developer.apple.com/documentation/uikit/uikeyboardlayoutguide/3752189-followsundockedkeyboard)
- [textViewDidEndEditing(_:)](https://developer.apple.com/documentation/uikit/uitextviewdelegate/1618628-textviewdidendediting)
- [didEnterBackgroundNotification](https://developer.apple.com/documentation/uikit/uiapplication/1623071-didenterbackgroundnotification)
- [willDeactivateNotification](https://developer.apple.com/documentation/uikit/uiscene/3197924-willdeactivatenotification)
- [description](https://developer.apple.com/documentation/swift/customstringconvertible/description)
- [init(context:)](https://developer.apple.com/documentation/coredata/nsmanagedobject/1640602-init)
- [UIActivityViewController](https://developer.apple.com/documentation/uikit/uiactivityviewcontroller)
- [init(activityItems:applicationActivities:)](https://developer.apple.com/documentation/uikit/uiactivityviewcontroller/1622019-init)
- [dataTask(with:completionHandler:)](https://developer.apple.com/documentation/foundation/urlsession/1407613-datatask)
- [Core Location](https://developer.apple.com/documentation/corelocation)
- [Getting the Userโs Location](https://developer.apple.com/documentation/corelocation/getting_the_user_s_location)
- [Adding Location Services to Your App](https://developer.apple.com/documentation/corelocation/adding_location_services_to_your_app)
- [Requesting Authorization for Location Services](https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services)
- [Using Lightweight Migration](https://developer.apple.com/documentation/coredata/using_lightweight_migration)
## API
- [Open Weather - Current weather data](https://openweathermap.org/current)
# ํ ํ๊ณ
<details>
<summary> ํ ํ๊ณ ๋ณด๊ธฐ (ํด๋ฆญ) </summary>
<div markdown="1">
### ์ฐ๋ฆฌ ํ์ด ์ํ ์
- ์๊ฐ ์ฝ์์ ํ๋ฃจ๋ ๋น ์ง์์ด ์ ์ง์ผฐ์ต๋๋ค.
- ์๋ก ์ํ๋ ์ ์ ์์งํ๊ฒ ์ด์ผ๊ธฐํ๊ณ ์ ํ์ํ์ฌ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋์ถํ์ต๋๋ค.
- ์ ์ฉํ ๊ธฐ์ ์ ์ถฉ๋ถํ ์ดํดํ๋ฉด์ ํ๋ก์ ํธ๋ฅผ ์งํํ์์ต๋๋ค.
### ์๋ก ์นญ์ฐฌํ ์
- ์ฝ๋์ด -> ํ๋ชจ๋ฆฌ
- ํ์์ ์๊ฒฌ์ ์ ๋ค์ด์ฃผ๊ณ , ๋ณธ์ธ์ ์๊ฒฌ๋ ์ ๊ทน์ ์ผ๋ก ํํํ์์ต๋๋ค. ํญ์ ์๊ฒฌ์ ๊ทผ๊ฑฐ๊ฐ ์์๊ธฐ ๋๋ฌธ์ ํ์๊ฐ ์๋งํ์ต๋๋ค.
- ๋ํ๋ฅผ ์ ์ด๋์ด์ค์ ์ฆ๊ฒ๊ฒ ํ์
ํ ์ ์์์ต๋๋ค.
- ํ๋ชจ๋ฆฌ -> ์ฝ๋์ด
- ์ฝ๋์ด๋ ์ ๋ง ๊ผผ๊ผผํ์
์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๋๋ ๊ธ๋ฐฉ ์ฐพ์ ์ ์์๊ณ , ์ ์๊ธฐ๋ฅผ ์ถฉ๋ถํ ์ ๋ค์ด์ฃผ์๊ณ ์ ์ ํ ๋์์ ์ฃผ์
์ ์ ๋ง ๋ง์ด ๋ฐฐ์ธ ์ ์๋ ๊ธฐํ์์ต๋๋ค.
- ์ด๋ ค์ด ๊ฐ๋
์ ์ ์ดํดํ์๊ณ ์ ์ค๋ช
ํด ์ฃผ์
์ ๋ฃ๋ ์ ๋ ์ดํดํ๊ธฐ๊ฐ ๋ฌด์ฒ ์ฌ์ ์ต๋๋ค.
</div>
</details>