프로젝트 기간 : 2022.08.16 화 ~ 2022.09.04 일
리뷰어 : Wody
- 📜 프로젝트 소개
- 👥 팀원
- 💾 개발환경 및 라이브러리
- 💡 핵심경험
- 🕰 타임라인
- 🧑💻 코드 설명
- 📱 구현 화면
- 📁 파일 요약 정리
- ⛹🏻♀️ STEP 1 트러블 슈팅
- ⛹🏻♀️ STEP 2 트러블 슈팅
- ⌨️ 커밋 규칙
- 🔗 참고 링크
📔 나만의 일기장을 만들어봅시다! Core location을 사용하여 사용자의 해당 위치를 파악하고, open weather api를 사용하여 실시간 날씨를 받아옵니다. 입력받은 사용자의 일기와 날씨정보를 Core data 방식으로 앱 내부에 저장하는 일기장 어플입니다.
재재(ZZBAE) | 그루트(Groot) (절대권력자) |
---|---|
Github | Github |
- Date Formatter의 지역 및 길이별 표현의 활용
- Text View의 활용
- 코어데이터 모델 생성
- 코어데이터 모델 및 DB 마이그레이션
- 테이블뷰에서 스와이프를 통한 삭제기능 구현
- Text View Delegate의 활용
- Open API의 활용
- Core Location의 활용
Step 1 첫째 주
날짜 | 내용 |
---|---|
8/16(화) | 명세에 있는 공식문서, WWDC, 영상 등 공부 |
8/17(수) | ListView 구현 및 dateFormatter 적용 |
8/18(목) | DetailView 구현 및 RegisterView, 키보드 구현 |
8/19(금) | Step1 PR 및 리드미작성 |
Step 2 둘째 주
날짜 | 내용 |
---|---|
8/22(월) | Step1 리팩토링 |
8/23(화) | 개인공부 |
8/24(수) | 개인공부 및 Step1 리팩토링, 머지 |
8/25(목) | Core Data CRUD 구현, DetailView 자동저장 구현 및 RegisterView 자동저장 구현 |
8/26(금) | Step2 PR 및 리드미작성 |
Step 3 셋째 주
날짜 | 내용 |
---|---|
8/29(월) | Step2 리팩토링 |
8/30(화) | Step2 리팩토링 및 머지 |
8/31(수) | Step3 해당 개인 공부 |
9/1(목) | 날씨 API 받아서 날씨 icon 불러오기 |
9/2(금) | 사용자 지역별 날씨 icon 불러오기 수정 및 Step3 PR |
9/4(일) | Step3 리팩토링 및 리드미작성 |
├── CoreDataManager.swift
├── DataModel
│ ├── DiaryModel.swift
│ └── WeatherModel.swift
├── Diary
│ ├── Diary.xcdatamodeld
│ │ ├── Diary.xcdatamodel
│ │ │ └── contents
│ │ └── DiaryWithWeather.xcdatamodel
│ │ └── contents
│ ├── Info.plist
│ ├── Resources
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ └── SceneDelegate.swift
│ ├── Scene
│ │ ├── DataTask
│ │ │ └── DataTaskViewController.swift
│ │ ├── DiaryDetail
│ │ │ ├── Controller
│ │ │ │ └── DiaryDetailViewController.swift
│ │ │ └── View
│ │ │ └── DiaryDetailView.swift
│ │ ├── DiaryList
│ │ │ ├── Controller
│ │ │ │ └── DiaryListViewController.swift
│ │ │ ├── Model
│ │ │ │ ├── DiaryData.swift
│ │ │ │ ├── DiaryDataManager.swift
│ │ │ │ └── WeatherDataManager.swift
│ │ │ └── View
│ │ │ └── DiaryTableViewCell.swift
│ │ └── DiaryRegister
│ │ ├── Controller
│ │ │ └── DiaryRegisterViewController.swift
│ │ └── View
│ │ └── DiaryRegisterView.swift
│ ├── extension
│ │ └── Double+extension.swift
│ └── protocol
│ └── DiaryDataManagerProtocol.swift
├── Diary+CoreDataClass.swift
├── Diary+CoreDataProperties.swift
├── DiaryTests
│ └── DiaryTests.swift
└── README.md
STEP 1
일기장 리스트를 테스트 하기위한 Data 구조체
- Sample Json Data를 Decode해서 배열로 반환하는 타입
일기장 List를 구현하기 위한 TableViewCell 타입
TableView를 구현하고 Scene의 전환을 위한 Controller 역할
DiaryListViewController에서 데이터를 전달받아 DiaryDetailView에 전달하는 Controller 역할 DataSendable 채택하여 데이터를 전달(Delegation 전달방식 사용)
일기장의 내용을 편집할 수 있는 뷰
새로운 일기장을 생성할 수 있는 뷰 (이번 step에서는 뷰의 layout만 구성)
Controller간 데이터 전달을 위한 Protocol
convertData()
라는 지역과 언어에 따라 해당 언어를 바꿔주는 DateFormatter 함수
DummyData의 Json 데이터의 디코딩이 정상적으로 되는지 확인하는 테스트
STEP 2
CoreData를 활용하여 사용자가 적는 일기장 내용을 CRUD (Creat, Read, Update, Delete) 해주는 기능을 관리하는 파일
새롭게 적은 일기의 내용을 DiaryListView에 전달하여 추가하는 Controller 역할
일기의 내용을 새로 적을 수 있는 뷰
decoding한 DiaryModel을 타입으로 갖는 diaryItems로 가지고 있는 프로토콜
사용자가 일기 내용을 새로 적은 데이터를 담는 구조체
DiaryData를 인스턴스화하여 provider이란 프로퍼티로 가지고 있는 구조체
STEP 3
openAPI Get Reqeuest를 사용해 실시간 날씨정보와 Icon 이미지를 받아오기 위한 Data Manager
openAPI 사이트에서 받아올 날씨와 아이콘 WeatherData를 배열로 가지고 있는 WeatherModel
-
문제점
- TextView에 text를 설정했을 때 자동으로 스크롤이 되지만, text의 길이가 화면을 넘지 못해 스크롤이 생기지는 않아 제목이 잘리는 문제가 있었습니다.
-
해결 과정
- detailTextView를 초기화해주는 클로저에서 contentOffset을 변경해줬지만, 해결하지 못했습니다.
- 초기화 당시엔 문제가 없지만, Text를 설정해주면서 스크롤이 내려가는 문제가 발생함을 알 수 있었습니다.
-
해결방법
- text 설정 후 TextView의 Offset을 초기화 해주는 방법으로 문제를 해결하였습니다.
detailTextView.contentOffset = CGPoint(x: 0, y: 0)
문제화면 | 해결화면 |
---|---|
- 어떤 방식으로 백그라운드 진입을 확인할 것인가에 대한 고민
- sceneDidEnterBackground를 사용해서 백그라운드 자동저장 기능을 구현 시 모든 화면에서 저장 메서드를 호출하는 문제가 있었습니다.
- sceneDelegate의
sceneDidEnterBackground
를 사용하는 방법으로 자동저장 기능을 구현했지만, 모든 화면에서 백그라운드 이동 시 일기장 등록 ViewController에 있는 자동저장 메서드가 호출되는 문제가 있었습니다.
- sceneDelegate의
- 현재 window의
NavigationViewContoller
의topViewContoller
을 확인하는 방법으로 저장이 필요한ViewContoller
인지 확인해서 호출하는 방법을 사용했습니다.func sceneDidEnterBackground(_ scene: UIScene) { guard let navigationViewController = window?.rootViewController as? UINavigationController else { return } let topViewContoller = navigationViewController.topViewController switch topViewContoller { case let viewController as DiaryRegisterViewController: viewController.saveDiaryData() case let viewController as DiaryDetailViewController: viewController.saveDiaryData() default: break } }
- feat : 기능 추가 (새로운 기능)
- refactor : 리팩토링 (네이밍 수정 등)
- style : 스타일 (코드 형식, 세미콜론 추가: 비즈니스 로직에 변경 없음)
- docs : 문서 변경 (문서 추가, 수정, 삭제)
- test : 테스트 (테스트 코드 추가, 수정, 삭제: 비즈니스 로직에 변경 없음)
- chore : 기타 변경사항 (빌드 스크립트 수정 등)
[STEP 1]
Adaptivity and Layout
Positioning content relative to the safe area
Positioning content within layout margins
Making apps adaptive part 1
Making apps adaptive part 2
DateFormatter
UITextView
tableView(_:trailingSwipeActionsConfigurationForRowAt:)
UITableViewController VS UIViewController + UITableView
hugging priority, compression priority