CoreData
를 활용하여 만든 일기장 앱으로 수정이 간편하고, 날짜별로 날씨 정보를 함께 저장합니다.
Diary - 새 일기 작성 | Diary - 일기 수정 |
---|---|
Diary - 공유, 삭제(메인) | Diary - 더보기(디테일) |
---|---|
Diary - Alert Error | Diary - Toast Error |
---|---|
┌── Diary
│ ├── Network
│ │ ├── Location
│ │ ├── URLComponents
│ │ ├── NetworkAPI
│ │ └── WeatherAPI
│ ├── Error
│ │ ├── DecodingManager
│ │ ├── NetworkAPIDefinition
│ │ └── CacheStore
│ ├── CoreData
│ │ ├── CoreDataManager
│ │ ├── PersistentContainer
│ │ ├── Diary
│ │ │ ├── Diary v2
│ │ │ └── Diary
│ │ └── MappingFile
│ ├── Model
│ │ ├── DiaryModel
│ │ └── CellIdentifier
│ ├── View
│ │ ├── LaunchScreen
│ │ └── DiaryCell
│ ├── Controller
│ │ ├── DiaryViewController
│ │ └── DiaryDetailViewController
│ ├── Protocol
│ │ ├── Shareable
│ │ └── Toastable
│ ├── Extension
│ │ ├── DateFormatter+
│ │ ├── UITextView+
│ │ └── Array+
│ ├── Application
│ │ ├── AppDelegate
│ │ └── SceneDelegate
│ └── Resource
│ ├── Assets
│ └── Info
│
└── README.md
- 다이어리의 작성 일자에 대한 날짜 표현 형식을 사용자에 맞게 표현해 주기 위한 방법이 필요했습니다. JSON 파일에 저장된 날짜는 시스템 시간으로 1970년을 기준으로 한
Double
타입의 값이었기 때문에 사용자에게 표현하는 형식을 선택해야 했습니다.
-
JSON 파일에서 받아온 날짜를 디바이스의 지역에 맞는 형식으로 표현해 주기 위해 아래와 같이 Locale을 사용하였습니다.
extension DateFormatter { static let diaryFormatter = { let formatter = DateFormatter() formatter.dateStyle = .long formatter.locale = Locale.current return formatter }() } // 적용 let date = Date(timeIntervalSince1970: diaryModel[indexPath.row].date) let formattedDate = DateFormatter.diaryFormatter.string(from: date)
지역에 맞게 날짜의 형식을 변경해 주는 diaryFormatter를 사용하여 JSON 데이터를 디코딩 한 값인 date(Double 타입)을 매개변수로 전달하였습니다.
CoreData
를 활용하는데 어려움이 많았습니다. 그중에서 새 일기장을 만들고 아무것도 입력하지 않은 상태로 다시 나오거나 입력을 하다가 다 지우고 나오면 생성되지 않아야 된다고 생각을 하였는데 생성이 되는 문제점이 발생했습니다.
-
textView
의 내용이 비어있으면delete
를 해주어 해결했습니다.func saveDiary() { guard !contentTextView.text.isEmpty else { CoreDataManager.shared.deleteDiary(item: diary) return } let contents = contentTextView.text.split(separator: "\n") let title = String(contents[0]) let body = contents.dropFirst().joined(separator: "\n") if contents.isEmpty { saveContents(title: "", body: "") } else { saveContents(title: title, body: body) } }
Diary
를Creat
하는 위치에 따라tableView
에cell
이 추가되는 시점이 달랐습니다. 두 번째 화면인DiaryDetailViewController
에서Diary
를 생성하고 저장하는 경우 이전 화면으로 돌아와tableView
를 확인하면 목록에 없는 문제가 발생하였습니다. 다음 화면으로 넘어갔다가 다시 돌아오면 그제야cell
이tableView
에 추가되었습니다.tableView
에cell
이 그려지는 시점이 문제였습니다.
-
이를 해결하기 위해
Diary
를 첫 화면인DiaryViewController
에서 생성하여 다음 화면인DiaryDetailViewController
로 넘겨주는 작업을 수행하였습니다.let action = UIAction { _ in let diary = CoreDataManager.shared.createDiary() let diaryDetailViewController = DiaryDetailViewController(diary: diary, isUpdate: false) self.navigationController?.pushViewController(diaryDetailViewController, animated: true) }
생성한
Diary
에 입력을 하는 경우save
또는update
동작을 분리하기 위하여isUpdate
를 통해 구분하였습니다.
-
확인을 해보니 날짜를 받아오는
label
의 사이즈가 변동이 되면서 발생된 문제점이라Hugging
을 주어서 해결했습니다.private let dateLabel = { let label = UILabel() label.font = .preferredFont(forTextStyle: .body) label.setContentHuggingPriority(.defaultHigh, for: .horizontal) return label }()
-
textView
의 내용이 비어있으면delete
를 해주어 해결했습니다.func saveDiary() { guard !contentTextView.text.isEmpty else { CoreDataManager.shared.deleteDiary(item: diary) return } let contents = contentTextView.text.split(separator: "\n") let title = String(contents[0]) let body = contents.dropFirst().joined(separator: "\n") if contents.isEmpty { saveContents(title: "", body: "") } else { saveContents(title: title, body: body) } }
Diary
를Creat
하는 위치에 따라tableView
에cell
이 추가되는 시점이 달랐습니다. 두 번째 화면인DiaryDetailViewController
에서Diary
를 생성하고 저장하는 경우 이전 화면으로 돌아와tableView
를 확인하면 목록에 없는 문제가 발생하였습니다. 다음 화면으로 넘어갔다가 다시 돌아오면 그제야cell
이tableView
에 추가되었습니다.tableView
에cell
이 그려지는 시점이 문제였습니다.
-
Diary
를 첫 화면인DiaryViewController
에서 생성하여 다음 화면인DiaryDetailViewController
로 넘겨주는 작업을 수행하였습니다.let action = UIAction { _ in let diary = CoreDataManager.shared.createDiary() let diaryDetailViewController = DiaryDetailViewController(diary: diary, isUpdate: false) self.navigationController?.pushViewController(diaryDetailViewController, animated: true) }
생성한
Diary
에 입력을 하는 경우save
또는update
동작을 분리하기 위하여isUpdate
를 통해 구분하였습니다.
-
dateLabel
의 높이에 맞추어서 날씨 아이콘의 크기가 변경되도록 제약조건을 잡아주고dateLabel
의setContentHuggingPriority
을required
로 가장 높게 잡아주어 해결했습니다.private let dateLabel = { let label = UILabel() label.font = .preferredFont(forTextStyle: .body) label.setContentHuggingPriority(.required, for: .vertical) label.setContentHuggingPriority(.defaultHigh, for: .horizontal) return label }() private let weatherIconImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit return imageView }()
API KEY
를 코드에 직접 입력하여 사용하는 경우API KEY
가 외부에 드러날 수 있다는 문제점이 있었습니다. 팀원과의 협업을 위해git
을 통해 코드를 업로드 하는 과정에서 입력했던API KEY
가 함께 업로드 되었습니다.
-
API KEY
를 감추기 위해plist
파일을 생성하여 외부에 드러나지 않도록 숨겼습니다.API KEY
를 위해 생성한 파일을git
에 저장하고 이후git
에서 추적하지 않도록 설정하여 실제KEY
값을 사용하였습니다.git update-index --skip-worktree Diary/Resource/WeatherInfo.plist
- 🍎 Swift API Design Guidelines
- 🍏 Apple Developer - UINavigationController
- 🍏 Apple Developer - UITextView
- 🍏 Apple Developer - UIKeyboardLayoutGuide
- 🍏 Apple Developer - Date
- 🍏 Apple Developer - DateFormatter
- 🍏 Apple Developer - Adding support for languages and regions
- 🍏 Apple Developer - Locale
- BLOG : 김종권의 iOS 앱 개발 알아가기 - SwiftLint 적용 방법
- BLOG : Dr.kim의 나를 위한 블로그 - 화면에 딱 맞는 UITextView 만들기
- BLOG : Hacking with Swift - Fixing the keyboard: NotificationCenter
hoon ♓️ | Karen ♉️ |
---|---|
https://github.com/Hoon94 | https://github.com/karenyang835 |
⏰ 타임 라인 (펼쳐보기)
날 짜 | 내 용 |
---|---|
2023.08.28. | 📝 프로젝트에서 필요로 하는 핵심기능 공부 - CoreData |
2023.08.29. | 🖨️ SwiftLint 라이브러리 추가✴️ tableView 구현✴️ navigationController 구현 |
2023.08.30. | ✴️ parseData 메서드 구현✴️ custom cell 구현✴️ diaryFormatter 구현💥 DiaryDetailViewController 화면이동 추가 구현 |
2023.08.31. | ✴️ DiaryDetailViewController 레이아웃 구현💥 keyboard 에 맞춰 제약조건 수정 |
2023.09.01. | 💥 DiaryCell 선택시 다음 화면으로 이동✴️ CellIdentifier 구현✴️ DataAsset 을 불러오지 못하는 경우 presentAlert 메소드 추가💥 중복 사용하는 프로퍼티를 상수로 선언 💥 UITableViewDelegate 와 UITableViewDataSource extension 분리💥 diaryList 로 네이밍 변경✍️ README 수정 |
2023.09.04. | 📝 프로젝트에서 필요로 하는 핵심기능 공부 - CoreData CRUD |
2023.09.05. | 📝 프로젝트에서 필요로 하는 핵심기능 공부 - UITextViewDelegate |
2023.09.06. | 📝 프로젝트에서 필요로 하는 핵심기능 공부 - UISwipeActionsConfiguration |
2023.09.07. | ✴️ CoreData Diary Entity 생성 ✴️ Coredata loadDiary 메소드 추가 ✴️ CoreData saveDiary 메소드 추가✴️ Coredata deleteDiary 메소드 추가 |
2023.09.08. | ✴️ CoreData updateDiary 메소드 추가✴️ keyboard Done 버튼 추가💥 DiaryDetailViewController 의 화면 레이아웃을 하나의 contentTextView 로 통합 |
2023.09.09. | ✴️ CoreDataManager 추가 ✴️ 백그라운드로 진입하는 경우 일기 자동저장 구현 💥 기존 CRUD 코드 통합 |
2023.09.11. | ✴️ showActivityView 메서드 추가 ✴️ Shareable Protocol 생성 ✴️ Alert 기능 추가 💥 tableView swipe action 공유기능 추가 |
2023.09.12. | ✴️ Array extension 추가 💥 CoreDataManager 을 제너릭타입 활용으로 변경 💥 isUpdated 상수명 수정💥 closure 순환참조 방지를 위한 weak self 수정 |
2023.09.13. | 💥 configureCell 메서드 매개변수 타입 변경 💥 Shareable 프로토콜 제네릭 타입으로 변경 |
2023.09.14. | ✴️ WeatherAPI 생성 및 API KEY 숨기기 ✴️ NetworkManager 생성 및 fetchWeather 메서드 구현 ✴️ decodeData 메서드 구현 및 모델 생성✴️ CoreLocation 기반 위치정보 가져오기 구현 |
2023.09.15. | 💥 prepareForReuse 메서드 수정💥 CacheStore 로 네이밍 변경💥 NetworkAPI 수정 ✴️ NetworkAPI 생성 💥 Cell 재사용을 위한 초기화 및 날씨 icon autolayout 수정 ✴️ CoreData 마이그레이션 및 fetchIconImage 메서드 추가 |
2023.09.16. | ✴️ showToast 메서드 생성 💥 if let 으로 수정하여 가독성 향상 🖨️ 스토리보드 삭제 |