# ์ผ๊ธฐ์žฅ[STEP2] > ๐Ÿ“Œ ํ™”๋ฉด์— ์ œ๋ชฉ, ์ž‘์„ฑ์ผ์ž, ํ•œ์ค„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ๋ณด์—ฌ์ง€๋Š” ์ผ๊ธฐ์žฅ ์•ฑ์ž…๋‹ˆ๋‹ค. > **ํ•ต์‹ฌ ๊ฐœ๋…** UITextView, UITableView, DateFormatter, NotificationCenter, CoreData, UISwipeActionsConfiguration, UIActivityViewController ## ๐Ÿ“š ๋ชฉ์ฐจ</br> - [ํŒ€์›์†Œ๊ฐœ](#-ํŒ€์›-์†Œ๊ฐœ) - [ํŒŒ์ผํŠธ๋ฆฌ](#-ํŒŒ์ผํŠธ๋ฆฌ) - [์‹œ๊ฐํ™”๋œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ](#์‹œ๊ฐํ™”๋œ-ํ”„๋กœ์ ํŠธ-๊ตฌ์กฐ) - [ํƒ€์ž„๋ผ์ธ](#-ํƒ€์ž„๋ผ์ธ) - [์‹คํ–‰ํ™”๋ฉด](#-์‹คํ–‰ํ™”๋ฉด) - [ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…](#-ํŠธ๋Ÿฌ๋ธ”-์ŠˆํŒ…) - [์ฐธ๊ณ ์ž๋ฃŒ](#-์ฐธ๊ณ ์ž๋ฃŒ) ## ๐Ÿง‘โ€๐Ÿ’ป ํŒ€์› ์†Œ๊ฐœ</br> | <img src="https://github.com/devKobe24/images/blob/main/%E1%84%86%E1%85%AE%E1%86%AB.jpeg?raw=true" width="200" height="200"/> | <img src="https://github.com/devKobe24/BranchTest/blob/main/IMG_5424.JPG?raw=true" width="200" height="200"/> | | :-: | :-: | | [**Moon(๋ฌธ)**](https://github.com/hojun-jo) | [**Kobe(์ฝ”๋น„)**](https://github.com/devKobe24) | ## ๐Ÿ—‚๏ธ ํŒŒ์ผํŠธ๋ฆฌ</br> ``` . โ”œโ”€โ”€ Diary โ”‚ย ย  โ”œโ”€โ”€ Model โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ DiaryDateFormatter.swift โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ Protocol โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ IdentifierGenerator.swift โ”‚ย ย  โ”œโ”€โ”€ View โ”‚ย ย  โ”‚ โ”œโ”€โ”€ Base.lproj โ”‚ย ย  โ”‚ โ”‚ย ย  โ””โ”€โ”€ LaunchScreen.storyboard โ”‚ย ย  โ”‚ โ””โ”€โ”€ DiaryTableViewCell.swift โ”‚ย ย  โ”œโ”€โ”€ Controller โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ DetailDiaryViewController.swift โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ DiaryMainViewController.swift โ”‚ย ย  โ”œโ”€โ”€ Application โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ AppDelegate.swift โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ DiaryPersistentContainer.swift โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ SceneDelegate.swift โ”‚ย ย  โ”œโ”€โ”€ Extension โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ Array+.swift โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ UITableViewCell+.swift โ”‚ย ย  โ””โ”€โ”€Resource โ”‚ย ย  ย ย  โ””โ”€โ”€ Assets.xcassets โ”‚ย ย  ย ย  โ”œโ”€โ”€ AccentColor.colorset โ”‚ย ย  ย ย  โ”‚ย ย  โ””โ”€โ”€ Contents.json โ”‚ย ย  ย ย  โ”œโ”€โ”€ AppIcon.appiconset โ”‚ย ย  ย ย  โ”‚ย ย  โ””โ”€โ”€ Contents.json โ”‚ย ย  ย ย  โ””โ”€โ”€ Contents.json โ””โ”€โ”€ README.md ``` ## ๐Ÿ—บ๏ธ ์‹œ๊ฐํ™”๋œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ</br> <img src = "https://github.com/devKobe24/images/blob/main/Diary%5BSTEP2%5DUML.png?raw=true"> ## โฐ ํƒ€์ž„๋ผ์ธ</br> ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ๊ธฐ๊ฐ„ | 23.08.29.(ํ™”) ~ 23.09.15.(๊ธˆ) | ๋‚ ์งœ | ์ง„ํ–‰ ์‚ฌํ•ญ | | -------- | -------- | | 23.08.29.(ํ™”) | SwiftLint ์ ์šฉ.<br/>ํ…Œ์ด๋ธ” ๋ทฐ ์ƒ์„ฑ, Autolayout ์ ์šฉ.<br/>DiaryTableViewCell ์ƒ์„ฑ ๋ฐ ๊ตฌํ˜„.<br/>UITableViewCell Extension ๊ตฌํ˜„.<br/>Main.storyboard ์‚ญ์ œ.<br/>DiaryTableViewCell UI ์ˆ˜์ •<br/>๋„ค๋น„๊ฒŒ์ด์…˜ ์•„์ดํ…œ ์ถ”๊ฐ€<br/>DateFormatter extension ๊ตฌํ˜„| | 23.08.30.(์ˆ˜) | Diary DTO ์ƒ์„ฑ<br/>DecodeError ์ƒ์„ฑ ๋ฐ ๊ตฌํ˜„<br/>์ƒ˜ํ”Œ ์—์…‹ ์ถ”๊ฐ€<br/>์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋””์ฝ”๋”ฉ<br/>NSAttributedString ๋ฐ˜ํ™˜ ํ•จ์ˆ˜ ์ˆ˜์ •<br/>fetchDate ํ•จ์ˆ˜ ์ƒ์„ฑ ๋ฐ ๊ตฌํ˜„.<br/>formatCreatedAt ํ•จ์ˆ˜ ์ƒ์„ฑ ๋ฐ ๊ตฌํ˜„.<br/>DiaryDateFormatter ์ƒ์„ฑ ๋ฐ ๊ตฌํ˜„ | 23.08.31.(๋ชฉ) | DateFormatter, UITextView ๊ฐœ๋… ํ•™์Šต<br/> | 23.09.01(๊ธˆ) | ์ผ๊ธฐ์žฅ [STEP1-1] README ์ž‘์„ฑ.<br/> | 23.09.02(ํ† ) | DetailDiaryViewController ์ƒ์„ฑ<br>TextView ๊ตฌํ˜„.<br/>TextViewDelegate ์„ค์ •<br>keyboardDismissMode ์„ค์ • | 23.09.06(์ˆ˜) | TextView keyboardDismissMode ์˜ต์…˜ ์ถ”๊ฐ€<br>์ถ”์ƒํ™” ๋ ˆ๋ฒจ ํ†ต์ผ<br>์ ‘๊ทผ์ œํ•œ์ž ์ˆ˜์ •<br>Array extension ์ƒ์„ฑ ๋ฐ subscript ๊ตฌํ˜„<br>index ์ ‘๊ทผ์„ safe subscript๋กœ ์ˆ˜์ •<br>iOS 15 ๋ฒ„์ „์„ ๊ธฐ์ค€์œผ๋กœ diaryTextView layout constraints ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ.<br/> | 23.09.08(๊ธˆ) | ์ผ๊ธฐ์žฅ [STEP1] README ์ž‘์„ฑ.<br/> | 23.09.09(ํ† ) | ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ํšŒ์˜ ๋ฐ ๊ฐœ๋… ํ•™์Šต.<br/> | 23.09.10(์ผ) | tableView(_ :, didSelectRowAt:) ์ƒ์„ฑ ๋ฐ ํ™”๋ฉด ๋ณ€๊ฒฝ ๋กœ์ง ๊ตฌํ˜„.<br>tableView(_ :, trailingSwipeActionsConfigurationForRowAt: ) ์ƒ์„ฑ ๋ฐ ์Šค์™€์ดํ”„ ์‚ญ์ œ ๊ธฐ๋Šฅ ๊ตฌํ˜„.<br>ableView(_ :, trailingSwipeActionsConfigurationForRowAt: )ํ•จ์ˆ˜ ๋‚ด๋ถ€ ์Šค์™€์ดํ”„ share ๊ธฐ๋Šฅ ๊ตฌํ˜„.<br><br/> | 23.09.11(์›”) | ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ํšŒ์˜ ๋ฐ ๊ฐœ๋… ํ•™์Šต.<br/> | 23.09.12(ํ™”) | core data ์—๋Ÿฌ ์ˆ˜์ • ๋ฐ leftBarButtonItem์„ backBarButtonItem์œผ๋กœ ๋ณ€๊ฒฝ<br/> | 23.09.13(์ˆ˜) | ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ํšŒ์˜ ๋ฐ ๊ฐœ๋… ํ•™์Šต.<br/> | 23.09.14(๋ชฉ) | ํ”„๋กœ์ ํŠธ ๊ด€๋ จ ํšŒ์˜ ๋ฐ ๊ฐœ๋… ํ•™์Šต.<br/> | 23.09.15(๊ธˆ) | ์ด์ „ ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜ ์‹œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋กœ ์ €์žฅ๋˜์ง€ ์•Š๋˜ ์˜ค๋ฅ˜ ์ˆ˜์ •<br>์ผ๊ธฐ์žฅ [STEP2] README ์ž‘์„ฑ.<br/> ## ๐Ÿ“บ ์‹คํ–‰ํ™”๋ฉด</br> - STEP1 ์ผ๊ธฐ์žฅ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ์‹คํ–‰ํ™”๋ฉด ๐ŸŽฌ </br> <img src = "https://github.com/devKobe24/images/blob/main/%E1%84%8B%E1%85%B5%E1%86%AF%E1%84%80%E1%85%B5%E1%84%8C%E1%85%A1%E1%86%BCstep2-g.gif?raw=true"> ## ๐Ÿ”จ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… ### 1๏ธโƒฃ **StackView ๋‚ด๋ถ€์—์„œ Label์˜ Height๊ฐ€ ์žกํžˆ์ง€ ์•Š๋Š” ํ˜„์ƒ.**</br> ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ StackView ๋‚ด๋ถ€์—์„œ Label์˜ Height๊ฐ€ ์žกํžˆ์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.</br>height is ambiguous for UILabel ๊ฒฝ๊ณ ๊ฐ€ ์ƒ๊ฒจ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.**</br> ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธ diaryTitle๊ณผ dateAndPreview์˜ content hugging priority ๊ฐ€ ๊ฐ™์•„ ์ƒ๊ธฐ๋Š” ํ˜„์ƒ์ด์˜€์Šต๋‹ˆ๋‹ค.</br>๋”ฐ๋ผ์„œ diaryTitle์— .defaultHigh + 1 ๊ฐ’์„ ์ฃผ์—ˆ๊ณ , dateAndPreview์—๋Š” .defaultHigh๊ฐ’์„ ์ฃผ์–ด ๊ฐ๊ฐ ๋‹ค๋ฅธ content hugging priority๊ฐ’์„ ์ฃผ์–ด ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.** ```swift import UIKit class DiaryTableViewCell: UITableViewCell { private let diaryTitle: UILabel = { let label = UILabel() label.font = UIFont.preferredFont(forTextStyle: .title2) label.setContentHuggingPriority(.defaultHigh + 1, for: .vertical) return label }() private let dateAndPreview: UILabel = { let label = UILabel() label.font = UIFont.preferredFont(forTextStyle: .body) label.setContentHuggingPriority(.defaultHigh, for: .vertical) return label }() } ``` ### 2๏ธโƒฃ **NSAttributedString์ด ์ ์šฉ๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ.** </br> ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ [__NSCFConstantString renderingMode]: unrecognized selector sent to instance 0x10aa5a2e8 ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์›์ธ์€ NSAttributedString.Key.font์— ํ•„์š”ํ•œ ํƒ€์ž…์ด UIFont์˜€์œผ๋‚˜ UIFont.TextStyle์„ ์‚ฌ์šฉ ์ค‘์ด์—ˆ์Šต๋‹ˆ๋‹ค.** ```swift private func convertAttributedString(text: String, font: UIFont.TextStyle) -> NSAttributedString { let attributes = [NSAttributedString.Key.font: font as Any] as [NSAttributedString.Key : Any] let attributedString = NSAttributedString(string: text, attributes: attributes) return attributedString } ``` ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> ๐Ÿ™‹โ€โ™‚๏ธ**NSAttributedString.Key.font์— UIFont ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.**</br> ```swift private func convertAttributedString(text: String, font: UIFont) -> NSAttributedString { let attributes = [NSAttributedString.Key.font: font as Any] as [NSAttributedString.Key : Any] let attributedString = NSAttributedString(string: text, attributes: attributes) return attributedString } ``` ### 3๏ธโƒฃ NSAttributedString์˜ ๊ฐ€์šด๋ฐ ์ •๋ ฌ ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ ๋ฌธ์ž์—ด ์ž์ฒด์˜ ๋ชจ์–‘์ด ์•„๋ž˜ ์ด๋ฏธ์ง€์™€ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— UILabel์˜ baselineAdjustment๋กœ ๊ฐ€์šด๋ฐ ์ •๋ ฌ์„ ๋งž์ถœ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** <img src = "https://github.com/devKobe24/images/blob/main/NSAttributedString%E1%84%86%E1%85%AE%E1%86%AB%E1%84%8C%E1%85%A6%E1%84%8C%E1%85%A5%E1%86%B7.png?raw=true"></br> ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธNSAttributedString.Key.baselineOffset์„ ์ด์šฉํ•ด ์ž‘์€ ๋ฌธ์ž ๋ถ€๋ถ„์˜ baseline์„ ์˜ฌ๋ฆฌ๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.**</br> <img src = "https://github.com/devKobe24/images/blob/main/NSAttributedString%E1%84%92%E1%85%A2%E1%84%80%E1%85%A7%E1%86%AF%E1%84%8C%E1%85%A5%E1%86%B7.png?raw=true"></br> ```swift private func attributedDateAndPreview(data: Diary, font: UIFont) -> NSMutableAttributedString { let text = "\(formatCreatedAt(data.createdAt)) \(data.body)" let attributedString = NSMutableAttributedString(string: text) let attributes: [NSAttributedString.Key: Any] = [ .font: font, .baselineOffset: 2 ] attributedString.addAttributes(attributes, range: (text as NSString).range(of: data.body)) return attributedString } ``` ### 4๏ธโƒฃ **ํ…์ŠคํŠธ๋ฅผ ๊ธธ๊ฒŒ ์ž‘์„ฑ์‹œ ํ‚ค๋ณด๋“œ์— ๊ฐ€๋ฆฌ๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ.** ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ ํ…์ŠคํŠธ๊ฐ€ ๊ธธ์–ด์ง์— ๋”ฐ๋ผ ํ‚ค๋ณด๋“œ ์ƒ๋‹จ์— ๊ฐ€๋ ค์ ธ ์˜๋„์ ์œผ๋กœ ํ‚ค๋ณด๋“œ๋ฅผ ๋‚ด๋ฆฌ๊ฑฐ๋‚˜ ์œ ์ €๊ฐ€ ์Šคํฌ๋กค๋ฅผ ํ•˜์—ฌ ํ…์ŠคํŠธ๋ฅผ ๋ด์•ผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.** ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธ ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์„ผํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ `UIResponder.keyboardWillHideNotification`์™€ `UIResponder.keyboardWillShowNotification`๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐํ•œ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.**</br> ```swift extension DetailDiaryViewController { private func setupKeyboardEvent() { if #unavailable(iOS 15.0) { NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil ) } } @objc private func keyboardWillShow(_ sender: Notification) { guard let userInfo = sender.userInfo, let keyboardFrame = userInfo[ UIResponder.keyboardFrameEndUserInfoKey ] as? CGRect else { return } diaryTextView.contentInset = UIEdgeInsets( top: .zero, left: .zero, bottom: keyboardFrame.height, right: .zero ) } @objc private func keyboardWillHide() { diaryTextView.contentInset = UIEdgeInsets() } } ``` ### 5๏ธโƒฃ **์ผ๊ธฐ์˜ ๋งจ ์ฒซ ์ค„์€ ์ผ๊ธฐ์˜ ์ œ๋ชฉ์ด ๋˜๊ณ , ๊ทธ ๋‹ค์Œ ์ค„๋ถ€ํ„ฐ ๋ณธ๋ฌธ์ด ๋˜๋Š” ๋กœ์ง.** ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ ์ผ๊ธฐ์˜ ๋งจ ์ฒซ ์ค„์€ ์ผ๊ธฐ์˜ ์ œ๋ชฉ์ด ๋˜๊ฒŒ ํ•˜๊ณ , ๊ทธ ๋‹ค์Œ ์ค„๋ถ€ํ„ฐ ๋ณธ๋ฌธ์ด ๋˜๋„๋ก ํ•˜๋Š” ๋กœ์ง์„ ๋งŒ๋“œ๋Š” ๋ถ€๋ถ„์—์„œ ํ…์ŠคํŠธ ๋ทฐ์˜ ์ฒซ ๋ฒˆ์งธ ์ค„๊ณผ ๊ทธ ๋‹ค์Œ ์ค„์„ ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆ„์–ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์–ด ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.** ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธํ…์ŠคํŠธ ๋ทฐ์˜ ๋งจ ์ฒซ ์ค„์€ ์ผ๊ธฐ์˜ ์ œ๋ชฉ์ด ๋˜๊ณ , ๊ทธ ๋‹ค์Œ ์ค„๋ถ€ํ„ฐ ๋ณธ๋ฌธ์ด ๋˜๋„๋ก ํ•˜๋Š” ๋กœ์ง์— ๋Œ€ํ•˜์—ฌ ๋งŽ์€ ๊ณ ๋ฏผ์„ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.</br>split(separator:), ๋ฐฐ์—ด, dropFirst(_:)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋กœ์ง์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ…์ŠคํŠธ ๋ทฐ์˜ ํ…์ŠคํŠธ์— "\n" ์ค„๋ฐ”๊ฟˆ์„ ๊ธฐ์ค€์œผ๋กœ String.SubSequence ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  ๊ทธ ๋ฐฐ์—ด์˜ index 0๋ฒˆ์งธ๋ฅผ ์ผ๊ธฐ์˜ ์ œ๋ชฉ์œผ๋กœ ๋งŒ๋“ค๊ณ , dropFirst(์ œ๋ชฉ.count)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ œ๋ชฉ count ์ด์ƒ์€ ๋ณธ๋ฌธ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.**</br> ```swift let splitedText = diaryTextView.text.split(separator: "\n") let title = String(splitedText[safe: 0] ?? .init()) let body = String(diaryTextView.text.dropFirst(title.count)) ``` ### 6๏ธโƒฃ **๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ง„์ž… ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ.** ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ ์ปจํ…์ŠคํŠธ๋งŒ ์ €์žฅํ•  ๊ฒฝ์šฐ ์ผ๊ธฐ์—์„œ ์ˆ˜์ • ์ค‘์ธ ๋‚ด์šฉ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์œˆ๋„์šฐ๋ฅผ ํ†ตํ•ด ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ฐ€์ ธ์™€ ์ €์žฅํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•  ๋“ฏํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹œ๋„ ํ–ˆ์œผ๋‚˜ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.**</br> ```swift func sceneDidEnterBackground(_ scene: UIScene) { guard let diaryViewController = window?.rootViewController?.navigationController?.topViewController as? DetailDiaryViewController else { return } diaryViewController.saveDiaryData() // persistentContainer?.saveContext() } ``` ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธ ๋ฃจํŠธ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์˜€๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.**</br> ```swift func sceneDidEnterBackground(_ scene: UIScene) { guard let navigationController = window?.rootViewController as? UINavigationController, let diaryViewController = navigationController.topViewController as? DetailDiaryViewController else { return } diaryViewController.saveDiaryData() } ``` ### 7๏ธโƒฃ **์ด์ „ ํ™”๋ฉด์œผ๋กœ ์ „ํ™” ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ.** ### ๐Ÿ”’ **๋ฌธ์ œ์ ** ๐Ÿ”’</br> **๐Ÿšจ backBarButtonItem์„ ์ด์šฉํ•ด ์ด์ „ ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜ํ•  ๊ฒฝ์šฐ UIBarButtonItem์˜ action์œผ๋กœ ์ง„์ž…ํ•˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๋กœ ์ €์žฅํ•˜์ง€ ๋ชป ํ•˜๋Š” ์ƒํ™ฉ์ด ์ผ์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค.**</br> ```swift private func configureNavigationItem(date: Date = Date()) { ... navigationItem.backBarButtonItem = UIBarButtonItem(title: "์ผ๊ธฐ์žฅ", style: .plain, target: self, action: #selector(didTapBackToMainButton)) ... } @objc private func didTapBackToMainButton() { saveDiaryData() navigationController?.popViewController(animated: true) } ``` ### ๐Ÿ”‘ **ํ•ด๊ฒฐ๋ฐฉ๋ฒ•** ๐Ÿ”‘</br> **๐Ÿ™‹โ€โ™‚๏ธ viewWillDisappear์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋„๋ก ํ•˜์—ฌ ํ™”๋ฉด ์ „ํ™˜ ์‹œ ํ•ญ์ƒ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.**</br> ```swift override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) saveDiaryData() } ``` ## ๐Ÿ“‘ ์ฐธ๊ณ ์ž๋ฃŒ - [๐Ÿ“ƒ Adaptivity and Layout](https://developer.apple.com/design/human-interface-guidelines/layout) - [๐Ÿ“ƒ UIKit: Apps for Every Size and Shape](https://www.wwdcnotes.com/notes/wwdc18/235/) - [๐ŸŽฅ Making apps adaptive part 1](https://www.youtube.com/watch?v=hLkqt2g-450) - [๐ŸŽฅ Making apps adaptive part 2](https://www.youtube.com/watch?v=s3utpBiRbB0) - [๐Ÿ“ƒ DateFormatter](https://developer.apple.com/documentation/foundation/dateformatter) - [๐Ÿ“ƒ UITextView](https://developer.apple.com/documentation/uikit/uitextview) - [๐Ÿ“ƒ NotificationCenter](https://developer.apple.com/documentation/foundation/notificationcenter) - [๐Ÿ“ƒ UIResponder](https://developer.apple.com/documentation/uikit/uiresponder) - [๐Ÿ“ƒ contentInset](https://developer.apple.com/documentation/uikit/uiscrollview/1619406-contentinset) - [๐Ÿ˜บ SwiftLint](https://github.com/realm/SwiftLint) - [๐Ÿ“ƒ Core Data](https://developer.apple.com/documentation/coredata) - [๐ŸŽฅ Making Apps with Core Data](https://developer.apple.com/videos/play/wwdc2019/230/) - [๐Ÿ“ƒ UITextViewDelegate](https://developer.apple.com/documentation/uikit/uitextviewdelegate) - [๐Ÿ“ƒ UISwipeActionsConfiguration](https://developer.apple.com/documentation/uikit/uiswipeactionsconfiguration)