ํ๋ก์ ํธ ๊ธฐ๊ฐ: 2022.06.13 ~ 2022.07.01 ํ์: ์ฐ๋กฑ์ฐจ, Red ๋ฆฌ๋ทฐ์ด: ์จ๋
๐ ์ผ๊ธฐ์ฅ ๋๋ง์ ์ผ๊ธฐ๋ฅผ ๋ง๋ค์ด ๋ณด์ธ์! ์ ์ฅ์ ๊น๋นกํ์ จ๋ค๊ตฌ์? ๊ฑฑ์ ์์ต๋๋ค. ์๋์ ์ฅ ๋ฉ๋๋ค!
- ์ฒซ์งธ์ฃผ : ํ๋ฉด๊ตฌ์ฑ, ํค๋ณด๋, Core Data CRUD ๊ตฌํ
- ๋์งธ์ฃผ : Core Data๋ฅผ ์ด์ฉํ ๊ธฐ๋ฅ ๊ตฌํ, TableView ์ธ์ธํ ๋์๊ตฌํ, alert ๊ตฌํ
- ์ ์งธ์ฃผ : ๋คํธ์ํน์ ํตํ์ฌ ๋ ์จ์ ๋ณด ๋ฐ์์ค๊ธฐ ๋ฐ ์ด๋ฏธ์ง ์ฝ์
- ํค๋ณด๋ ์ฌ๋ผ์ค๊ณ ๋ด๋ ค๊ฐ๋๊ฑฐ์ ๋ฐ๋ฅธ View ๋ณ๊ฒฝ
- iOS ๋ฎ์ ๋ฒ์ ์๋ฎฌ๋ ์ดํฐ ์คํ
๐ค๋ฌธ์
์๋ ์ฝ๋์ ๊ฐ์ด ํค๋ณด๋ ๊ด๋ จํ์ฌ ๋ ์ด์์์ ์ฃผ๋ฉด textFied ๋ textView ๊ฐ ํค๋ณด๋์ ๊ฐ๋ ค์ง์ง ์๊ฒ ์์์ bottom ๋ ์ด์์์ ์์ ํ๋ค.
textView.bottomAnchor.constraint(equalTo: keyboardLayoutGuide.topAnchor).isActive = true
ํ์ง๋ง ์์ ๊ธฐ๋ฅ์ iOS 15๋ฒ์ ๋ถํฐ ์ง์ํ๊ธฐ ๋๋ฌธ์ ๋ฎ์ ๋ฒ์ ์์๋ ์คํ๋์ง ์์๋ค.
๐ํด๊ฒฐ
if #available(iOS 15.0, *)
๋ฅผ ์ฌ์ฉํด์ iOS 15.0 ๋ณด๋ค ๋ฒ์ ์ด ๋ฎ๋ค๋ฉด, Notification์ ์ด์ฉํด ํค๋ณด๋๊ฐ ๋ํ๋ ๋, ๋ฉ์๋๋ฅผ ํตํด์ ์๋์ ์คํ ๋ ์ด์์์ ์ ์ฉํด ์ฃผ์๋ค.
textViewBottomConstraint = textView.bottomAnchor.constraint(
equalTo: safeAreaLayoutGuide.bottomAnchor,
constant: -height // ์ฌ๊ธฐ์ height ๋ ํค๋ณด๋์ ๋์ด
)
์ด๋ ๊ธฐ์กด์ ์ ์ฉ๋ ์คํ ๋ ์ด์์์ ํด์ ํด์ค์ผ๋๊ธฐ ๋๋ฌธ์ ๋ณ์๋ก ๊ด๋ฆฌ๋ฅผ ํด์ผํ๋ค.
@objc private func keyBoardShow(notification: NSNotification) {
guard let userInfo: NSDictionary = notification.userInfo as? NSDictionary else {
return
}
guard let keyboardFrame = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as? NSValue else {
return
}
let keyboardRectangle = keyboardFrame.cgRectValue
let keyBoardHeight = keyboardRectangle.height
detailView.changeTextViewHeight(keyBoardHeight)
}
ํค๋ณด๋์ ๋์ด๋ Notification ์ ์ด์ฉํ๋ฉด ์์ ์ฝ๋์ฒ๋ผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
๐ค๋ฌธ์
๋ฎ์ ๋ฒ์ ์ iOS ์๋ฎฌ๋ ์ดํฐ๋ฅผ ๋๋ฆด ์๊ฐ ์์๋ค.
๐ํด๊ฒฐ
์์ชฝ ์๋ฎฌ๋ ์ดํฐ ์ ํํ๋ ์ฐฝ์์ Download Simulators ๋ฅผ ์ ํํ์ฌ ๋ฎ์ ๋ฒ์ ์ ์๋ฎฌ๋ ์ดํฐ๋ฅผ ์ค์นํ๋ฉด ๋๋ค. ํ์ง๋ง ๋น๋๋๋ ๋ฒ์ ์ ์ค์ ์ ๋ฐ๋ผ ์คํ์ด ๋์ง ์์์๋ ์์ผ๋ ์ฃผ์ํด์ผํ๋ค.
- Core Data Fetch ๋ฌธ์
- ViewModel ํ๋๋ฅผ ๋๊ฐ์ ViewController ๊ฐ ๋๋ ์ ์ฌ์ฉํด๋ ๋๋๊ฐ?
๐ค๋ฌธ์
์ค๋ช
: CoreData์์ fetch๋ก ๊ฐ์ ธ์จ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ๋ฐ๋ก ์ ๊ทผํ ๋ ค๊ณ ํ ๋ ์๊ธฐ๋ ๋ฌธ์ .(๋ค๋ฅธ ํ๋ค์๋ ์ด๋ฌํ ๋ฌธ์ ๊ฐ ์์๋ค. ์ค๋ฅ๋ฌธ๋ Expected DiaryData but found DiaryData๋ก ์ด์ํ๋ค.)
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด as [AnyObjcet]
์ผ๋ก ํ๋ณํ์ ์์ผฐ๋ค.
๐ํด๊ฒฐ
์ ์ฅํ ๋ NSManagedObject ํ์
์ผ๋ก ์ ์ฅ์ ํ์๋๊ฒ ๋ฌธ์ ๊ฐ ๋์๋ค. ์ ์ฅํ ๋ ์ฌ์ฉํ ๋ฐ์ดํฐ ๋ชจ๋ธ(DiaryData)๋ก ์ ์ฅํด์ผ ๋ฌธ์ ๊ฐ ์ผ์ด๋์ง ์๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ฅํ๋ ๋ก์ง์ ๋ณ๊ฒฝํ์ฟ๋ค. ์ดํ ์ฝ์ด์ฌ๋ as [AnyObjcet]
๋ก ๋ณํํ์ง ์์๋ ์ค๋ฅ๊ฐ ๋์ง์์๋ค.
guard let diaryData = NSEntityDescription.insertNewObject(
forEntityName: DiaryInfo.entityName,
into: context
) as? DiaryData else {
throw CoreDataError.createError
}
๐ค๋ฌธ์
MainViewController
์ DetailVewController
๊ฐ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๊ฐ (DiaryCoreData) ๋์ผํ๋ค๊ณ ์๊ฐ ๋์ด์ TableViewModel
์์ ์ด๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๊ณ ์์๋ค.
์ด๋ค ๋ฐฉ์์ผ๋ก ViewModel ์ ๋๋ ์ฌ์ฉํด์ผ ํ๋์ง์ ๊ดํ ๋ฌธ์ ๊ฐ ์์๋ค.
1๏ธโฃ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ
Delegateํจํด
์ ์ฌ์ฉํด์ DetailViewController
๊ฐ CoreData
๋ฅผ ๋ณ๊ฒฝํ ๋ MainViewController
๊ฐ ์ฒ๋ฆฌํ๊ฒ ๋ ๊ตฌ์ฑ์ด๋ค.
(ViewModel
์ด MainViewController
์๋ง ์์ผ๋ฏ๋ก)
extension MainViewController: UpdateDelegateable {
func updatae(diaryInfo: DiaryInfo) {
do {
try viewModel.update(data: diaryInfo)
try viewModel.loadData()
mainView.reloadData()
} catch {
alertMaker.makeErrorAlert(error: error)
}
}
func delete(diarInfo: DiaryInfo) {
do {
try viewModel.delete(data: diarInfo)
try viewModel.loadData()
mainView.reloadData()
} catch {
alertMaker.makeErrorAlert(error: error)
}
}
}
protocol UpdateDelegateable: UIViewController {
func updatae(diaryInfo: DiaryInfo)
func delete(diarInfo: DiaryInfo)
}
final class DetailViewController: UIViewController {
...
weak var delegate: UpdateDelegateable?
...
}
DetailViewController ์์ ์ผ์ด๋ ์ฌ๊ฑด์ MainViewController ๋ฅผ ํตํด ์ฒ๋ฆฌํด์ผ ํ๋ค๋ ๊ตฌ์กฐ๊ฐ ์กฐ๊ธ์ ์ด์ํ๋ค.
2๏ธโฃ๋๋ฒ์งธ ๋ฐฉ๋ฒ
DetailViewController์ TableViewModel ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ฒ ํ์ฌ, MainViewController ์ DetailVewController ๋ชจ๋ TableViewModel ์ ์ง์ ์ ๊ทผํ๋๋ก ํ๋ ๋ฐฉ๋ฒ
final class MainViewController: UIViewController {
...
private var viewModel: TableViewModel<DiaryUseCase>
...
}
final class DetailViewController: UIViewController {
...
private var viewModel: TableViewModel<DiaryUseCase>
...
}
๐ํด๊ฒฐ
๊ฒฐ๊ตญ ๋ค๋ฅธ ๋ทฐ๋ชจ๋ธ์ ๋ง๋ค์ด์ ์ฒ๋ฆฌํ์๋ค. ์ ์ค์ผ์ด์ค๋ ๊ฐ์ด ๋ง๋ค์ด์คฌ๋ค. ๋ถ๋ฆฌํ ์ด์ ๋ ๋ทฐ ๋ชจ๋ธ์์ ๋ธ๋ฆฌ๊ฒ์ดํธ ํจํด์ ์ฌ์ฉํ์ฌ ๋ทฐ์ปจ์์์ ๋์์ ๋ฐ๋๋ ๋๊ฐ์ ๋ทฐ์ปจ์ด ์ฌ์ฉ๋๋ฉด์ ํ๋์ ๋ทฐ๋ชจ๋ธ์์ ์ฒ๋ฆฌํ๊ธฐ ๊ณค๋ํด์ก๋ค. ๋ํ ๋๊ฐ๋ฅผ ์ฌ์ฉํ๊ธฐ์ ์ต์ ํ๊ฐ ๋ ๋์์๋ค. ์ด๋ฌํ ์ด์ ๋ก ๋ค๋ฅธ ๋ทฐ๋ชจ๋ธ์ ๋ง๋ค์ด์คฌ๋ค.
๐ค๋ฌธ์
delete ๋ฒํผ share ๋ฒํผ์ ๋๋ ์๋ ๋์ํ๋ ๋ฉ์๋๊ฐ mainViewController ์ DetailViewController ์์ ์ฌ์ฉ๋๊ณ ์๋๋ฐ, ๋ ๋ก์ง์ด ์ ์ฌํ์ง๋ง ์ธ์ธํ ๋ถ๋ถ์ด ๋ค๋ฅด๋ค.
data ๋ฅผ ์ญ์ ํ๊ณ , ๊ณต์ ํ๋ handler
๋ฅผ MainViewController
์ DetailViewController
์์ ๋ชจ๋ ์ฌ์ฉ์๋ค.
๊ฐ์ ๋ก์ง์ด์ง๋ง ์ฐจ์ด๋
์ด๋ค controller
์์ TableViewModel
์ ์ ๊ทผํ๋๋ ์ด๋ค.
์ด ๋ ๋ก์ง์ด ๊ฒน์น๋ ๋ถ๋ถ์ด ๋ง๋ค๊ณ ์๊ฐ๋๋๋ฐ ๊ฐ์ ํด๋ก์ ๋ฅผ ๊ณต์ ํด์ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋์ง ๊ถ๊ธํ๋ค.
๐ํด๊ฒฐ
๊ฒฐ๊ตญ ๋ค๋ฅธ ๋ฉ์๋๋ผ ๊ทธ๋ฅ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํด์คฌ๋ค.
๐ค๋ฌธ์
์ดํ์ด ํํ๋ฉด์ผ๋ก ์ ํํ ๋ DetailView
ํ๋ฉด์ data ๋ฅผ ์๋ ์ ์ฅ ํด์ฃผ๊ธฐ ์ํด SceneDelegate
์ ์๋ ํํ๋ฉด์ผ๋ก ์ ํ๋ ๋ ๋ถ๋ฆฌ๋ sceneDidEnterBackground
๋ฉ์๋๋ฅผ ์ด์ฉํ๋ค.
1๏ธโฃ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ
AppDelegate
์์ delegate
ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ SceneDelegate
์์ ํธ์ถํ๋ ๋ฐฉ๋ฒ์ด๋ค. (AppDelegate
๋ ์ ์ญ์ ์ผ๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํจ์ผ๋ก).
์ด ๋ฐฉ๋ฒ์ ์์ ํด์ผ ํ๋ ์ฌํญ์ด ๋ง๊ณ , AppDelegate๊ฐ delegate ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ค๋ ๋จ์ ์ด ์๋ค.
2๏ธโฃ๋๋ฒ์งธ ๋ฐฉ๋ฒ
๋๋ฒ์งธ ๋ฐฉ๋ฒ์ SceneDelegate์์ ๋ทฐ๋ฅผ ํ์ธํด์ ๋ฉ์๋๋ฅผ ์คํํ๋ ๋ฐฉ๋ฒ์ด๋ค.
func sceneDidEnterBackground(_ scene: UIScene) {
((self.window?.rootViewController as? UINavigationController)?.topViewController as? DetailViewController)?.saveData()
}
๐ํด๊ฒฐ
์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ ํํ์ฌ ์์ฑํ์๋ค. ๋๋ฒ์งธ ๋ฐฉ๋ฒ์ ๊ฒฐ๊ตญ TopView๋ฅผ ๊ฐ์ ธ์์ผ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค. ํ์ง๋ง TopView๋ฅผ ์ ๋๋ก ๊ฐ์ ธ์ฌ๋ ค๋ฉด ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํด์ค์ผํ๋ค. ํ์ง๋ง ์ฐ๋ฆฌ๋ ๊ผผ๊ผผํ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํ์ง์๊ณ ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ ํํ๊ธฐ๋ก ํ๋ค.
- Rx ์์ด MVVM ๊ตฌ์กฐ
- Result ํ์ ์ผ๋ก ๋ณ๊ฒฝ
- UseCase
๐ค๋ฌธ์
์ฒ์์๋ MVVM ํจํด์ ์ต์ํ์ง ์์์ MVC ์ฒ๋ผ
MVVM ๊ตฌ์กฐ๋ฅผ ViewController ๊ฐ ViewModel ์ ํ๋กํผํฐ๋ฅผ ์ง์ ์ ๊ทผํด์ ํธ์ถํ๊ณ ์์ ํ๋ ๋ฐฉํฅ์ผ๋ก ์์ฑํ์๋ค.
(ํ๋ผ๋ฏธํฐ๋ก ํธ๋ค๋ฌ๋ฅผ ๋ฐ์์ ํธ๋ค๋ฌ๋ฅผ ViewController ์์ ํธ์ถํ๋๋ก ์์ ํ์๋ค.)
๐ํด๊ฒฐ
delegate๋ก Handler ๋ค์ ์์ฑํด ์ฃผ์ด์ Handler ๋ฅผ ํธ์ถํ๋ ์ฃผ์ฒด๊ฐ ViewController ๊ฐ ์๋ ViewModel ์ด ๋๊ฒ ํ์๋ค.
๊ณ์ธต ๋ณ๋ก ๊ธฐ๋ฅ์ ๋๋๊ณ ์ถํ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์ด๋ค ๊ตฌ์กฐ๋ก ๊ตฌ์ฑํด์ผ๋ ์ง ๋ง์ ๋์์ด ๋๊ฑฐ๊ฐ๋ค. ์ฐ๋ฆฌ MVVM ๊ตฌ์กฐ์์ ์ ํ ๊ท์น์ด ์๋ค.
- ๋ทฐ๋ชจ๋ธ์์ ๋ทฐ์ ๊ด๋ จ๋ ์ฝ๋๋ฅผ ์ฐ์ง์๋๋ค.(UIKit ์ ์ํฌํธํ์ง์๋๋ค.)
- ๋ทฐ๋ชจ๋ธ์ ์ ๊ทผํ ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ํด์ ๋ด๋ถ ํจ์๊ฐ ๋๋ฌ๋์ง ์๊ฒํ๋ค.
- ๋ทฐ - ๋ทฐ๋ชจ๋ธ - ์ ์ค์ผ์ด์ค ์ ์ญํ ์ ์ฌ๋ฐ๋ฅด๊ฒ ๋ถ๋ฆฌํ๋ค.
๐ค๋ฌธ์
CRUD ๋ฉ์๋๋ฅผ throws ๋ก ์์ฑํ๋๋ฐ ๋ฆฌ๋ทฐ์ด๊ป์ try catch ๋ฅผ ์ฌ์ฉํ์ง ์๋ ๋ฐฉ๋ฒ์ผ๋ก ์์ ํด ๋ณด๋ ๊ฒ์ด ์ด๋ป๊ฒ ๋๋ ์ด์ผ๊ธฐ ํด์ฃผ์
จ๋ค.
๐ํด๊ฒฐ
Result ํ์
์ ์ฌ์ฉํด์ Success ์ Failure ํ ๊ฐ์ฒด๋ฅผ ๋ฐ๋๋ก ์ค์ ํ๋ค.
- CoreData
- KeyBoard
- ActionSheet
- ActivityVeiw
- TableView Cell ์ญ์ , ์ถ๊ฐ
- TableView Swipe