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 2] Mary, Whales #134

Open
wants to merge 26 commits into
base: ic_9_whale
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fecc10b
:sparkles: Feat: Core Data 모델 생성 및 CRUD 구현
MaryJo-github Sep 5, 2023
971a07b
✨ Feat: 새 일기 추가 화면에서 자동으로 키보드 보여주는 기능 추가
WhalesJin Sep 5, 2023
03b05c1
✨ Feat: 일기 편집 화면에서 키보드가 숨김/해제 되도록 TapGesture 추가
WhalesJin Sep 5, 2023
eee7407
:sparkles: Feat: 일기 자동 저장 구현
MaryJo-github Sep 6, 2023
a200cfa
Revert ":sparkles: Feat: 일기 자동 저장 구현"
MaryJo-github Sep 6, 2023
5248c7b
:sparkles: Feat: 일기 자동 저장 구현
MaryJo-github Sep 6, 2023
5f79326
♻️ Refactor: CoreData에 저장된 DiaryContent 불러오기
WhalesJin Sep 6, 2023
ef67611
✨ Feat: 일기 편집 화면에 더보기 버튼 및 액션 시트 추가
WhalesJin Sep 6, 2023
fbc2d86
:recycle: Refactor: DiaryManager struct -> class 변경
MaryJo-github Sep 7, 2023
a180043
:sparkles: Feat: ActivityView 및 CheckDeleteAlert 구현 및 적용
MaryJo-github Sep 7, 2023
1fb5d7d
:recycle: Refactor: presentActivityView 메서드를 PresentableActivityView …
MaryJo-github Sep 8, 2023
0dcaad6
📝 Docs: Update README.md
WhalesJin Sep 8, 2023
1c89149
:recycle: Refactor: 일기장 내용이 비어있으면 저장하지 않도록 수정
MaryJo-github Sep 12, 2023
45db402
:sparkles: Feat: cell swipe시 공유 및 삭제 기능 추가
MaryJo-github Sep 12, 2023
936d211
✨ Feat: 문자열 로컬라이저 적용
WhalesJin Sep 12, 2023
a45087f
🐛 Fix: 빈 텍스트뷰 클릭 후 입력 시 데이터 저장 안되는 오류 수정
WhalesJin Sep 12, 2023
1ec8d4a
:adhesive_bandage: Chore: tableView 상수로 변경 및 configure 메서드 병합
MaryJo-github Sep 14, 2023
7eb44ef
:recycle: Refactor: String extension localized 프로퍼티 추가
MaryJo-github Sep 14, 2023
95dd5d9
:adhesive_bandage: Chore: 네이밍 수정
MaryJo-github Sep 15, 2023
8928097
✨ Feat: Logger 타입 생성해서 DiaryViewController에 주입
WhalesJin Sep 15, 2023
d838492
:recycle: Refactor: TableViewCell의 AutoLayout 변경
MaryJo-github Sep 15, 2023
cfecbc7
♻️ Refactor: if 문을 guard 문으로 로직 수정
WhalesJin Sep 15, 2023
c9e4490
:recycle: Refactor: ContainerManager를 DiaryManager에 병합
MaryJo-github Sep 16, 2023
dfc8a85
✨ Feat: 데이터 저장 및 삭제 실패시 Alert 띄우기
WhalesJin Sep 16, 2023
a3fae63
:sparkles: Feat: DiaryEditable 프로토콜 생성 및 DiaryManager에서 채택
MaryJo-github Sep 16, 2023
3883a95
♻️ Refactor: weak self 추가
MaryJo-github Feb 2, 2024
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
15 changes: 15 additions & 0 deletions Diary+CoreDataClass.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Diary+CoreDataClass.swift
// Diary
//
// Created by Mary & Whales on 2023/09/05.
//
//

import Foundation
import CoreData

@objc(Diary)
public class Diary: NSManagedObject {

}
27 changes: 27 additions & 0 deletions Diary+CoreDataProperties.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Diary+CoreDataProperties.swift
// Diary
//
// Created by Mary & Whales on 2023/09/05.
//
//

import Foundation
import CoreData

extension Diary {

@nonobjc public class func fetchRequest() -> NSFetchRequest<Diary> {
return NSFetchRequest<Diary>(entityName: "Diary")
}

@NSManaged public var title: String
@NSManaged public var body: String
@NSManaged public var timeInterval: Double
@NSManaged public var id: UUID

}

extension Diary: Identifiable {

}
16 changes: 16 additions & 0 deletions Diary.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
3C3C08F02AA6241D00C8D4CF /* DateFormatter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C3C08EF2AA6241D00C8D4CF /* DateFormatter+.swift */; };
3CCA1E772A9DBF56008683C3 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 3CCA1E762A9DBF56008683C3 /* .swiftlint.yml */; };
3CCA1E792A9F08C8008683C3 /* DiaryContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCA1E782A9F08C8008683C3 /* DiaryContent.swift */; };
444E73F82AAAFA940079BEE5 /* PresentableActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444E73F72AAAFA940079BEE5 /* PresentableActivityView.swift */; };
4495F2EF2A9CCF62007D5278 /* DiaryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4495F2EE2A9CCF62007D5278 /* DiaryTableViewCell.swift */; };
44A761BA2A9F100900C10AE2 /* DecodingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A761B92A9F100900C10AE2 /* DecodingManager.swift */; };
44A761BD2A9F142B00C10AE2 /* DataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A761BC2A9F142B00C10AE2 /* DataError.swift */; };
44A761BF2A9F163600C10AE2 /* DiaryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A761BE2A9F163600C10AE2 /* DiaryManager.swift */; };
44A761C12A9F7A6100C10AE2 /* EditingDiaryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A761C02A9F7A6100C10AE2 /* EditingDiaryViewController.swift */; };
44A762012AA5F96700C10AE2 /* UITableViewCell+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A762002AA5F96700C10AE2 /* UITableViewCell+.swift */; };
44A762032AA6031800C10AE2 /* ReuseIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A762022AA6031800C10AE2 /* ReuseIdentifiable.swift */; };
44A7622D2AA710F000C10AE2 /* Diary+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A7622B2AA710F000C10AE2 /* Diary+CoreDataClass.swift */; };
44A7622E2AA710F000C10AE2 /* Diary+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A7622C2AA710F000C10AE2 /* Diary+CoreDataProperties.swift */; };
44A762302AA712A200C10AE2 /* ContainerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A7622F2AA712A200C10AE2 /* ContainerManager.swift */; };
C739AE25284DF28600741E8F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C739AE24284DF28600741E8F /* AppDelegate.swift */; };
C739AE27284DF28600741E8F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C739AE26284DF28600741E8F /* SceneDelegate.swift */; };
C739AE29284DF28600741E8F /* DiaryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C739AE28284DF28600741E8F /* DiaryViewController.swift */; };
Expand All @@ -36,13 +40,17 @@
3C3C08EF2AA6241D00C8D4CF /* DateFormatter+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+.swift"; sourceTree = "<group>"; };
3CCA1E762A9DBF56008683C3 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
3CCA1E782A9F08C8008683C3 /* DiaryContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryContent.swift; sourceTree = "<group>"; };
444E73F72AAAFA940079BEE5 /* PresentableActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentableActivityView.swift; sourceTree = "<group>"; };
4495F2EE2A9CCF62007D5278 /* DiaryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryTableViewCell.swift; sourceTree = "<group>"; };
44A761B92A9F100900C10AE2 /* DecodingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingManager.swift; sourceTree = "<group>"; };
44A761BC2A9F142B00C10AE2 /* DataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataError.swift; sourceTree = "<group>"; };
44A761BE2A9F163600C10AE2 /* DiaryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryManager.swift; sourceTree = "<group>"; };
44A761C02A9F7A6100C10AE2 /* EditingDiaryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditingDiaryViewController.swift; sourceTree = "<group>"; };
44A762002AA5F96700C10AE2 /* UITableViewCell+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+.swift"; sourceTree = "<group>"; };
44A762022AA6031800C10AE2 /* ReuseIdentifiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReuseIdentifiable.swift; sourceTree = "<group>"; };
44A7622B2AA710F000C10AE2 /* Diary+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Diary+CoreDataClass.swift"; sourceTree = "<group>"; };
44A7622C2AA710F000C10AE2 /* Diary+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Diary+CoreDataProperties.swift"; sourceTree = "<group>"; };
44A7622F2AA712A200C10AE2 /* ContainerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerManager.swift; sourceTree = "<group>"; };
C739AE21284DF28600741E8F /* Diary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Diary.app; sourceTree = BUILT_PRODUCTS_DIR; };
C739AE24284DF28600741E8F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C739AE26284DF28600741E8F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -80,6 +88,7 @@
children = (
3CCA1E782A9F08C8008683C3 /* DiaryContent.swift */,
44A761BE2A9F163600C10AE2 /* DiaryManager.swift */,
44A7622F2AA712A200C10AE2 /* ContainerManager.swift */,
);
path = Model;
sourceTree = "<group>";
Expand All @@ -89,6 +98,7 @@
children = (
44A761B92A9F100900C10AE2 /* DecodingManager.swift */,
44A762022AA6031800C10AE2 /* ReuseIdentifiable.swift */,
444E73F72AAAFA940079BEE5 /* PresentableActivityView.swift */,
);
path = Utility;
sourceTree = "<group>";
Expand Down Expand Up @@ -141,6 +151,8 @@
C739AE18284DF28600741E8F = {
isa = PBXGroup;
children = (
44A7622B2AA710F000C10AE2 /* Diary+CoreDataClass.swift */,
44A7622C2AA710F000C10AE2 /* Diary+CoreDataProperties.swift */,
3C3C086B2AA1DD8D00C8D4CF /* Localizable.strings */,
3CCA1E762A9DBF56008683C3 /* .swiftlint.yml */,
C739AE23284DF28600741E8F /* Diary */,
Expand Down Expand Up @@ -268,6 +280,7 @@
buildActionMask = 2147483647;
files = (
44A761BA2A9F100900C10AE2 /* DecodingManager.swift in Sources */,
44A7622D2AA710F000C10AE2 /* Diary+CoreDataClass.swift in Sources */,
44A762032AA6031800C10AE2 /* ReuseIdentifiable.swift in Sources */,
C739AE29284DF28600741E8F /* DiaryViewController.swift in Sources */,
4495F2EF2A9CCF62007D5278 /* DiaryTableViewCell.swift in Sources */,
Expand All @@ -277,7 +290,10 @@
C739AE27284DF28600741E8F /* SceneDelegate.swift in Sources */,
44A761BD2A9F142B00C10AE2 /* DataError.swift in Sources */,
44A762012AA5F96700C10AE2 /* UITableViewCell+.swift in Sources */,
444E73F82AAAFA940079BEE5 /* PresentableActivityView.swift in Sources */,
44A762302AA712A200C10AE2 /* ContainerManager.swift in Sources */,
3C3C08902AA3AB6C00C8D4CF /* UIViewController+.swift in Sources */,
44A7622E2AA710F000C10AE2 /* Diary+CoreDataProperties.swift in Sources */,
3C3C08F02AA6241D00C8D4CF /* DateFormatter+.swift in Sources */,
C739AE2F284DF28600741E8F /* Diary.xcdatamodeld in Sources */,
44A761C12A9F7A6100C10AE2 /* EditingDiaryViewController.swift in Sources */,
Expand Down
60 changes: 53 additions & 7 deletions Diary/Controller/DiaryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
// last modified by Mary & Whales

import UIKit
import OSLog
havilog marked this conversation as resolved.
Show resolved Hide resolved

final class DiaryViewController: UIViewController {
private var diaryManager: DiaryManager
private let diaryManager: DiaryManager

private var tableView: UITableView = {
havilog marked this conversation as resolved.
Show resolved Hide resolved
let tableView = UITableView()
Expand All @@ -31,9 +32,15 @@ final class DiaryViewController: UIViewController {

configureView()
configureTableView()
setUpConstraints()
setupConstraints()
havilog marked this conversation as resolved.
Show resolved Hide resolved

}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

fetchDiaryContents()
tableView.reloadData()
}

private func configureView() {
Expand Down Expand Up @@ -70,7 +77,7 @@ final class DiaryViewController: UIViewController {
tableView.register(DiaryTableViewCell.self, forCellReuseIdentifier: DiaryTableViewCell.reuseIdentifier)
}

private func setUpConstraints() {
private func setupConstraints() {
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
Expand All @@ -81,10 +88,13 @@ final class DiaryViewController: UIViewController {

private func fetchDiaryContents() {
do {
try diaryManager.fetchDiaryContents(name: "sample")
try diaryManager.fetchDiaryContents()
} catch {
print(error.localizedDescription)
presentAlertWith(title: "데이터 불러오기 실패", message: "앱을 다시 실행해주십시오.", actionConfigs: ("확인", .default, nil))
os_log("%@", error.localizedDescription)
presentAlertWith(title: String(localized: "failedFatchDataAlertTitle"),
havilog marked this conversation as resolved.
Show resolved Hide resolved
message: String(localized: "failedFatchDataAlertMessage."),
preferredStyle: .alert,
actionConfigs: (String(localized: "failedFatchDataAlertAction"), .default, nil))
}
}
}
Expand Down Expand Up @@ -115,7 +125,7 @@ extension DiaryViewController: UITableViewDataSource {
}
}

extension DiaryViewController: UITableViewDelegate {
extension DiaryViewController: UITableViewDelegate, PresentableActivityView {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let diaryContents = diaryManager.diaryContents,
let diaryContent = diaryContents[safe: indexPath.row]
Expand All @@ -126,4 +136,40 @@ extension DiaryViewController: UITableViewDelegate {
showEditingDiaryViewController(with: diaryContent)
havilog marked this conversation as resolved.
Show resolved Hide resolved
tableView.deselectRow(at: indexPath, animated: true)
}

func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard let diaryContents = diaryManager.diaryContents,
let diaryContent = diaryContents[safe: indexPath.row]
else {
return nil
}

let share = UIContextualAction(
Copy link

Choose a reason for hiding this comment

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

escaping하는 closure에서 self를 잡을 때 메모리가 어떻게 되는지, 어떤 점을 주의해야하고 사용해야하는지 설명해주세요~

Copy link
Author

Choose a reason for hiding this comment

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

기본적으로 클로저 내부에서 self를 사용하는 경우 클로저는 self에 대한 강한 참조를 유지합니다. 그리고 만약 클로저 내부에서 self의 프로퍼티에 저장하는 것과 같이 self가 클로저에 대한 강한 참조를 유지하는 경우, self와 클로저 간 순환 참조가 발생하게 됩니다.
순환 참조가 발생하게되면 각 인스턴스가 할당 해제되는 것을 방지하여 앱에서 메모리 누수를 유발하기 때문에 주의하고 사용해야합니다.

style: .normal,
title: String(localized: "share")
) { (_, _, success: @escaping (Bool) -> Void) in

let diaryContentItem = diaryContent.title + diaryContent.body

self.presentActivityView(shareItem: diaryContentItem)
success(true)
}

let delete = UIContextualAction(
style: .destructive,
title: String(localized: "delete")
) { (_, _, success: @escaping (Bool) -> Void) in

self.presentCheckDeleteAlert { _ in
ContainerManager.shared.delete(id: diaryContent.id)
self.diaryManager.diaryContents?.remove(at: indexPath.row)
Copy link

Choose a reason for hiding this comment

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

  1. @escaping self 안에 다시 @escaping이 있을 경우 어떻게 될지 설명해주세요.

tableView.deleteRows(at: [indexPath], with: .fade)
}

success(true)
}

return UISwipeActionsConfiguration(actions: [delete, share])
}
}
104 changes: 96 additions & 8 deletions Diary/Controller/EditingDiaryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import UIKit

final class EditingDiaryViewController: UIViewController {
final class EditingDiaryViewController: UIViewController, PresentableActivityView {
private var diaryContent: DiaryContent

private let diaryTextView: UITextView = {
Expand All @@ -31,10 +31,22 @@ final class EditingDiaryViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

configureView()
setUpConstraints()
fillDiaryTextView()
setupConstraints()
setupDiaryTextView()
setObserver()
}

override func viewWillDisappear(_ animated: Bool) {
Copy link

Choose a reason for hiding this comment

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

뷰의 상태값을 가지고 어떤 행동을 하는 것은 위험할 것 같아요.
일기장 편집에서 나가는 행위는, 뒤로가기를 누르거나 스와이프 백 액션이 있을 수 있고,
그 액션들은 코드로 받을 수 있을거 같아요
또한 이렇게 어떤 조건이 아닐 때만 어떤 행동을 해야한다. 라는 context라면 guard를 쓰는게 더 자연스러워보여요

Choose a reason for hiding this comment

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


알려주신 것처럼 guard가 문맥상 더 자연스러워 보여서 수정하였습니다!!
cfecbc7

근데
뷰의 상태값을 가지고 어떤 행동을 하는 것은 위험할 것 같아요.
라는 부분이 잘 이해가 되지 않습니다.😓

코드 자체를 수정하는 방법으로는

  1. Back 버튼을 새로 구현하는 방법
@objc func tappedBackButton() {
    guard diaryTextView.text.isEmpty else {
        save()
        navigationController?.popViewController(animated: true)
        return
    }

    ContainerManager.shared.delete(id: diaryContent.id)
    navigationController?.popViewController(animated: true)
}
  1. willMove 메서드를 이용하는 방법
override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent)
    
    guard parent == nil else { return }
    guard diaryTextView.text.isEmpty else {
        save()
        return
    }

    ContainerManager.shared.delete(id: diaryContent.id)
}

이렇게 두 가지를 생각해보았지만 왜 viewWillDisappear를 쓰는 것이 위험한지, 셋 중 어떤 방법이 어떤 면에서 더 좋을지를 공부해보아도 확신이 들지 않아서 한 번 더 질문드립니다.
추가 설명을 부탁드려도 될까요?

super.viewWillDisappear(animated)

if diaryTextView.text.isEmpty {
ContainerManager.shared.delete(id: diaryContent.id)
return
}

save()
}

private func configureView() {
Expand All @@ -45,10 +57,37 @@ final class EditingDiaryViewController: UIViewController {
}

private func configureNavigationItem() {
let othersDiaryBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.bubble"),
style: .plain,
target: self,
action: #selector(tappedOthersButton))

navigationItem.rightBarButtonItem = othersDiaryBarButtonItem
navigationItem.title = diaryContent.date
}

private func setUpConstraints() {
@objc private func tappedOthersButton() {
let shareHandler: (UIAlertAction) -> Void = { _ in
let diaryContentItem = self.diaryContent.title + self.diaryContent.body
self.presentActivityView(shareItem: diaryContentItem)
}

let deleteHandler: (UIAlertAction) -> Void = { _ in
self.presentCheckDeleteAlert { _ in
ContainerManager.shared.delete(id: self.diaryContent.id)
self.navigationController?.popViewController(animated: true)
}
}

presentAlertWith(title: nil,
message: nil,
preferredStyle: .actionSheet,
actionConfigs: (String(localized: "share"), .default, shareHandler),
(String(localized: "delete"), .destructive, deleteHandler),
(String(localized: "cancel"), .cancel, nil))
}

private func setupConstraints() {
NSLayoutConstraint.activate([
diaryTextView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
diaryTextView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor),
Expand All @@ -57,9 +96,58 @@ final class EditingDiaryViewController: UIViewController {
])
}

private func fillDiaryTextView() {
if diaryContent.title.isEmpty == false {
diaryTextView.text = String(format: "%@\n\n%@", diaryContent.title, diaryContent.body)
private func setupDiaryTextView() {
if diaryContent.title.isEmpty == false || diaryContent.body.isEmpty == false {
diaryTextView.text = diaryContent.title + diaryContent.body
} else {
diaryTextView.becomeFirstResponder()
ContainerManager.shared.insert(diaryContent: diaryContent)
}

addGesture()
diaryTextView.delegate = self
}

private func addGesture() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tappedTextView(_:)))
diaryTextView.addGestureRecognizer(tapGesture)
}

@objc private func tappedTextView(_ sender: Any) {
if diaryTextView.isFirstResponder {
diaryTextView.resignFirstResponder()
} else {
diaryTextView.becomeFirstResponder()
}
}

private func setObserver() {
NotificationCenter.default.addObserver(self,
selector: #selector(enterBackground),
name: UIWindowScene.didEnterBackgroundNotification,
havilog marked this conversation as resolved.
Show resolved Hide resolved
object: nil)
}

@objc private func enterBackground() {
save()
}

private func save() {
guard let text = diaryTextView.text else { return }

if let index = text.firstIndex(of: "\n") {
diaryContent.title = String(text[text.startIndex ..< index])
diaryContent.body = String(text[index ..< text.endIndex])
} else {
diaryContent.title = text
}
Comment on lines +142 to +147
Copy link

Choose a reason for hiding this comment

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

개인적으로 요런 식으로 분리되면 좋을거 같은데 요것도 오답이다 는 아니구 고민해보면 좋을거 같은 포인트인거 같아요~
// 처음 뷰를 그리기 위한 일기 객체
// 텍스트뷰에 써진 텍스트
// 저장하기 위한 새로운 일기장 객체 생성
// 새로 만든 객체로 저장
// 성공하면 self의 일기장을 바꿔주거나


ContainerManager.shared.update(diaryContent: diaryContent)
}
}

extension EditingDiaryViewController: UITextViewDelegate {
func textViewDidEndEditing(_ textView: UITextView) {
save()
}
}
12 changes: 11 additions & 1 deletion Diary/Extension/UIViewController+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import UIKit
extension UIViewController {
func presentAlertWith(title: String?,
message: String?,
preferredStyle: UIAlertController.Style,
actionConfigs: (title: String?,
style: UIAlertAction.Style,
handler: ((UIAlertAction) -> Void)?)...) {
let alertController = UIAlertController(title: title,
message: message,
preferredStyle: .alert)
preferredStyle: preferredStyle)

for config in actionConfigs {
let action = UIAlertAction(title: config.title,
style: config.style,
Expand All @@ -25,4 +27,12 @@ extension UIViewController {

present(alertController, animated: true)
}

func presentCheckDeleteAlert(deleteHandler: @escaping (UIAlertAction) -> Void) {
presentAlertWith(title: String(localized: "checkDeleteAlertTitle"),
message: String(localized: "checkDeleteAlertMessage"),
preferredStyle: .alert,
actionConfigs: (String(localized: "checkDeleteAlertCancelAction"), .cancel, nil),
(String(localized: "checkDeleteAlertAction"), .destructive, deleteHandler))
}
}
Loading