- ๊ฐ๋ฐ๊ธฐ๊ฐ : 2022.11.07 ~ 2022.12.07(1๊ฐ์)
- 1์ธ ๊ฐ๋ฐ
- ์์น ๊ธฐ๋ฐ ์คํฐ๋ ๋งค์นญ ์๋น์ค
- Figma, Swagger, Confluence, Notion ์ฌ์ฉ
- ํด๋ํฐ ๋ฒํธ๋ก ์ธ์ฆ ๋ก๊ทธ์ธ / ํ์ํํด
- ์์น๊ธฐ๋ฐ ์๋น์ค๋ฅผ ์ด์ฉํ ์ฃผ๋ณ ์น๊ตฌ ํ์
- ์ฑํ ์์ฒญ / ์๋ฝ
- 1:1 ์ฑํ
MVVMRxSwiftRxDataSourceCompositional LayoutCodeBaseUISocketIORealmSwiftMapkitCoreLocationFirebaseAuthThenSnapkitAlamofireMultiSlider
FirebaseAuth๋ฅผ ์ด์ฉํ์ฌ ํด๋ํฐ ์ธ์ฆ ๋ก๊ทธ์ธ ๊ตฌํ ๋ฐ ์ ๊ท์์ ํ์ฉํ ์ ํจ์ฑ ๊ฒ์ฆCompositional Layout๊ณผRxDataSource๋ฅผ ์ฌ์ฉํ์ฌ ์์ฐ์ค๋ฌ์ด ์ ๋๋ฉ์ด์ ํจ๊ณผ๋ฅผ ์ฃผ์ด ์ฌ์ฉ์์๊ฒ ๋ ๋์ ๊ฒฝํ์ ์ ๊ณต- API๊ฐ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ์ด ๋๋๋ผ๋ ์ ์ง๋ณด์์ ํธ๋ฆฌํ๋๋ก
Alamofire์URLRequestConvertible์ ์ฌ์ฉํ์ฌRouter๋ชจ๋ํ Firebase Token Manager๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํ์ฌ Token๋ง๋ฃ์ ๊ฐฑ์ ๋๋๋ก ํจ์จ์ ์ธ ์ค๊ณSocket IO๋ฅผ ์ฌ์ฉํ์ฌ ์ค์๊ฐ 1:1 ์ฑํ ๊ตฌํ ๋ฐRealm์ ์ฌ์ฉํ์ฌ ๊ณผ๋ํ ์๋ฒ ํธ์ถ ๋ฐฉ์งCoreLocation๊ณผMapkit์ ์ฌ์ฉํ์ฌ ์ฃผ๋ณ ์คํฐ๋ ์น๊ตฌ๋ฅผ ๋ํ๋ผ ๋Custom Annotation์ผ๋ก ์ด๋ฏธ์ง ํ์- ํจ์จ์ ์ธ ๊ฐ๋ฐ์ ์ํด ์ฌ์ฌ์ฉ ๋ทฐ ์ ๊ทน ํ์ฉ ๋ฐ ๋์์ธ ์์คํ
๋์
Typo SystemCustom AlertCustom Button๋ฑ
-
์คํฐ๋ ๊ฒ์๋ทฐ ์ผ์ชฝ ์ ๋ ฌ ๋ ์ด์์ ์ด์
- ๊ธ์์์ ๋ฐ๋ผ ์ ์ ๋๋น๊ฐ ์ ๋์ ์ผ๋ก ๋ณ๋๋๊ฒ ํ๋ ๋ฐฉ๋ฒ์์ ๋ง์ ๊ณ ๋ฏผ์ ํ์๋๋ฐ, ์ ์ ๋ฒํผ์ ๋ฃ๊ณ Compositional Layout์ ์ก์๋ estimated ์ฌ์ด์ฆ๋ฅผ ์ฃผ์ด ํด๊ฒฐ.
static func fixedSpacedFlowLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize( widthDimension: .estimated(100), heightDimension: .absolute(32) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(150) ) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) group.interItemSpacing = NSCollectionLayoutSpacing.fixed(8) let sectionHeaderPadding: CGFloat = 32 let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = 8 section.contentInsets = NSDirectionalEdgeInsets( top: 16 + sectionHeaderPadding, leading: 16, bottom: 8, trailing: 16) let header = NSCollectionLayoutBoundarySupplementaryItem( layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(32)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading, absoluteOffset: CGPoint(x: 0, y: sectionHeaderPadding)) section.boundarySupplementaryItems = [header] let layout = UICollectionViewCompositionalLayout(section: section) return layout }
-
์คํฐ๋ ๊ฒ์๋ทฐ ์ค๋ณต๊ฐ ์ด์
- AnimatedDataSource๋ฅผ ์ธ๋ Hashableํ ๋ถ๋ถ์์ ๋ฌธ์ ๊ฐ ์๊ฒจ์ ๊ณ์ ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์. (Diffable๊ณผ ๋์ผ) RxDataSource ์น์ ๋ชจ๋ธ์ ๋ง๋ค๋ IdentifiableType๊ณผ Equatable์ ์ฑํํ์ฌ ๋ฐ์ดํฐ ๊ฐ์์ ๊ณ ์ ์ identity๋ฅผ ๊ฐ์ง๋๋ก ํ์ฌ ๋ฌธ์ ํด๊ฒฐ.
struct StudyList: Hashable { let study: String init(study: String) { self.study = study } } extension StudyList: IdentifiableType, Equatable { var identity: String { return UUID().uuidString } }
-
์์น ์ฐพ๊ธฐ๋ทฐ ์ ์ฌ์ฌ์ฉ ์ด์
- ๋ ๋ณด๊ธฐ ๋ทฐ๋ฅผ ํผ์น ๋ ์ ์ฌ์ฌ์ฉ ๋ฌธ์ ๊ฐ ์๊ฒจ์ ์ํ๋ ์ ์ด ์ด๋ฆฌ๊ณ ๋ซํ์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์. ์์ฑ๋๋ ์ ๊ฐฏ์๋งํผ ๋ฐฐ์ด์ Bool๊ฐ์ ๋ฃ์ด์ ๊ฐ๊ฐ์ ์ ์ด true, false ์ํ๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํ์ฌ ๋ฌธ์ ํด๊ฒฐ.
viewModel.nearSeSAC .withUnretained(self) .bind { vc, value in vc.mainView.setupEmptyStateView(value: value) vc.isSelected = Array<Bool>(repeating: false, count: value.count) } .disposed(by: disposeBag) viewModel.nearSeSAC .asDriver() .drive(mainView.tableView.rx.items) { [weak self] (tv, row, item) -> UITableViewCell in guard let cell = tv.dequeueReusableCell(withIdentifier: ProfileNickNameTableViewCell.reuseIdentifier, for: IndexPath.init(row: row, section: 0)) as? ProfileNickNameTableViewCell else { return UITableViewCell() } cell.firstLineView.moreButton.addTarget(self, action: #selector(self?.moreButtonTapped), for: .touchUpInside) cell.firstLineView.moreButton.tag = row cell.setupCellData(data: item, buttonType: .request) cell.requestButton.rx.tap .bind { _ in self?.presentAlert() self?.uid = item.uid print(item.uid) } .disposed(by: cell.disposeBag) if self?.isSelected[row] == true { cell.setupExpendedCell(hidden: false, image: Icon.uparrow) } else { cell.setupExpendedCell(hidden: true, image: Icon.downarrow) } return cell } .disposed(by: disposeBag)
-
์ฑํ UI ์ด์
- ์ฑํ ์ ๋ ฅ TextView ์ธ์ค ์ ํ์ TextView๊ฐ ํ์ฌ ๋ช ์ค ์ธ์ง ๊ณ์ฐํ์ฌ ๋์ด๋ฅผ ์ ํํ์๋๋ฐ, ๊ธ์๋ฅผ ์ง์ฐ๋ฉด์ TableView์์ ๋ ์ด์์์ด ๊นจ์ง๋ ํ์์ด ๋ฐ์. lessThan, greaterThan์ ๋ชจ๋ ์ค์ ํ์ฌ ๋ฌธ์ ํด๊ฒฐ.
func setupTextViewDidChange() { if textView.numberOfLine() > 3 { textView.snp.remakeConstraints { make in make.directionalHorizontalEdges.equalToSuperview().inset(16) make.bottom.equalTo(self.keyboardLayoutGuide.snp.top).offset(-16) make.height.equalTo(90) } textView.isScrollEnabled = true } else { textView.snp.remakeConstraints { make in make.directionalHorizontalEdges.equalToSuperview().inset(16) make.bottom.equalTo(self.keyboardLayoutGuide.snp.top).offset(-16) make.height.lessThanOrEqualTo(90) make.height.greaterThanOrEqualTo(52) } textView.isScrollEnabled = false } }
-
์ํ ์
- Rx์ MVVM์ด ์ต์ํ์ง ์์ ์ํ๋ก ํฐ ํ๋ก์ ํธ์ ์ ์ฉ์ํค๋ฉด์ ํ๋๋ผ ์ฒ์์๋ ์กฐ๊ธ ๊ณ ์์ ๋ง์ด ํ์ง๋ง, ๋ง์ ์ํ์ฐฉ์ค ๋์ ๋๋ฆ View์ ViewModel์ ๋ถ๋ฆฌํ๊ฒ ๋์๋ค.
- ๋ทฐ๋ฅผ ๋ง๋๋๊ฒ์ ๋ํ ์คํธ๋ ์ค๊ฐ ๊ต์ฅํ ์ปธ๋๋ฐ, ์ด๋ฒ์ ์ฌ๋ฌ๊ฐ์ง ์ด๋ ค์ ๋ณด์ด๋ ๋ทฐ๋ค์ ๋ง๋ค์ด ๋ณด๋ฉด์ ์ด์ ๋ทฐ๋ฅผ ๋ง๋๋๊ฒ์ ๋ํ ๊ฑฑ์ ๋ค์ด ๋ง์ด ํด์๋์๋ค.
- ์ฌ๋ฌ ์์ ์ต์ ์ ์ธ ๊ธฐ๋ฅ๋ค์ ์ ์ธํ๊ณ ํฐ ๊ธฐ๋ฅ๋ค์ ์ด์ ์ ๋๊ณ ์๋ก์ด ๊ธฐ์ ๋ค์ ๋ง์ด ์ ์ฉ์์ผ ๋ณด๋ ค๊ณ ํ๊ณ , ๊ฒฐ๊ณผ์ ์ผ๋ก ์๋์ ๋ง๊ฒ ์๋ก์ด ๊ธฐ์ ๋ค์ ๋ง์ด ๋ฐฐ์ฐ๊ฒ ๋์๋ค.
-
์๋ชปํ ์
- ์ฝ๋๋ฅผ ๋ชจ๋ ์ดํดํ๋ฉด์ ์ง๋ ค๊ณ ํ๋ ์ต๊ด๋๋ฌธ์ ๋์ ๊ตฌ์กฐ๋ค์ ์ดํดํ๋๋ฐ์ ์๊ฐ์ ๋๋ฌด ๋ง์ด ์์๊ณ , ๊ฒฐ๊ณผ์ ์ผ๋ก ์๊ฐ์ด ๋ถ์กฑํด์ ์ฝ๋์ ์ธ ๊ณ ๋ฏผ์ ๋ง์ด ํด๋ณด์ง ๋ชปํ๋ค.
- ์ด๋ฒ์ Commit์ ์ต๊ดํ ํ๊ณ , issue๋ฅผ ํตํด Github๋ฅผ ๊ด๋ฆฌํด ๋ณด๋ ค๊ณ ํ์ง๋ง ์คํจํ๋ค.
- ์ฑํ ๊ตฌํ์์ Realm๊ณผ Socket, Server๋ฑ ๋์ ๊ตฌ์กฐ๊ฐ ์ดํด๊ฐ ๋์ง ์์์ ๋๋ฌด ๋ง์ ์๊ฐ์ ๋ฒ๋ ธ๋ค. ๊ทธ๋ฅ ํด๋ณด๋ฉด์ ๋ชธ์ผ๋ก ํฐ๋ํ์ผ๋ฉด ํจ์ฌ ์๊ฐ์ ์ ์ฝํ ์ ์์์ ๊ฒ ๊ฐ๋ค.




