๐ iOS122 [iOS/Swift] Unit Test ๋? ๋จ์ ํ ์คํธ๋ผ๊ณ ํ๋ฉฐ ํ๋ก๊ทธ๋จ์ ๊ธฐ๋ณธ ๋จ์์ธ ๋ชจ๋์ ํ ์คํธ ํจ ๋ชจ๋์ด ์ ํด์ง ๊ธฐ๋ฅ์ ์ํํ๋์ง ํ ์คํธ ํจ(๋ชจ๋ ๋จ์๋ก ์ฝ๋๊ฐ ์์ฑ๋์ด์ผ ํจ) FIRST ๊ธฐ์ค Fast(๋น ๋ฆ) ํ ์คํธ๋ ๋น ๋ฅด๊ฒ ์คํ๋์ด์ผ ํจ Independent/Isolated(๊ณ ๋ฆฝ๋จ) ํ ์คํธ๋ ์๋ก ์ํ๋ฅผ ๊ณต์ ํด์๋ ์๋จ Repeatable(๋ฐ๋ณต์ ) ํ ์คํธ๋ฅผ ์คํํ ๋๋ง๋ค ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ด์ผ ํจ. ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ๊ณต๊ธ์(external data Provider ๋คํธ์ํฌ ์๋น์ค ๋ก์ง ๊ฐ์ ๊ฒ), ๋์์ฑ(concurrency) ๋ฌธ์ ๋ก ์ธํด ๊ฐํ์ ์ค๋ฅ ๋ฐ์ ํ ์ ์์ Self-validating(์๊ฐ ๊ฒ์ฆ) ํ ์คํธ๋ ์์ ํ ์๋ํ๋์ด์ผ ํจ. ๋ก๊ทธํ์ผ๋ก ํ๋ก๊ทธ๋๋จธ๊ฐ ํด์ํ๋ ๊ฒ์ด ์๋ ํ ์คํธ ์ผ์ด์ค์ ๋ํด “ํต๊ณผ” ๋๋ “์คํจ”์ฌ์ผํจ Time.. 2023. 4. 10. [RxSwift] passing viewmodel data to viewController ViewModel var currentSelectedCategoryIdx = PublishSubject() ์ด๊ธฐ๊ฐ์ด ํ์์๋ ๊ฒฝ์ฐ PublishSubject๋ก ViewModel์ property ์ ์ struct Input { // ์๋ต } struct Output { let changedCategoryIdx: Observable } viewController์์ ๊ฐ์ ๋ฐ์ ์ฌ์ฉํด์ผ ํ๋ฏ๋ก Output์ ๋ฐํํ Observable ํ์ ์ ์ ์ํด์ค func transform(input: Input) -> Output { let changedCategoryIdx = currentSelectedCategoryIdx.asObserver() return Output(changedCategoryIdx: change.. 2023. 3. 25. [iOS/Swift] UICollectionView Dynamic Height with AutoConstraint UICollectionViewDelegateFlowLayout์์ sizeForItemAt์ ์ ์ extension QuoteViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let margin = 16 + 16 let quote = viewModel?.updates[indexPath.row] return QuoteListCollectionViewCell.fittingSize(avai.. 2023. 3. 25. [iOS/Xcode] Pod file not found ์ด์ pod deintegrate pod install ์ด์ ์๊ธด ์ด์ ์ถ์ main branch, v1.0 branch ์์๋ v1.0์์๋ง ์ฌ์ฉํ๋ ค๊ณ ์ถ๊ฐํด ๋์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์๊ณ main์ผ๋ก ์ฎ๊ธฐ๋ฉด์ pod update -> ignore ์ถ๊ฐ ์ํ๊ณ ๋ค์ v1.0 ํ์ผ๋ก ์ด๋ -> ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชป ์ฐพ์ ํด๊ฒฐ ๋ฐฉ๋ฒ main์์ deintegrate ์ํค๊ณ ๋ค์ install, v1.0์์ deintergrate ์ํค๊ณ ๋ค์ install 2023. 3. 23. [Swift] FSCalendar ์ปค์คํ ์บ๋ฆฐ๋ ์ ๋ฆฌ FSCalendar ์ปค์คํ ์บ๋ฆฐ๋๋ฅผ ์์ฑํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ GitHub - WenchaoD/FSCalendar: A fully customizable iOS calendar library, compatible with Objective-C and Swift A fully customizable iOS calendar library, compatible with Objective-C and Swift - GitHub - WenchaoD/FSCalendar: A fully customizable iOS calendar library, compatible with Objective-C and Swift github.com ์์๋ณด๊ณ ์ ๋ฆฌํ๋๋ฐ ๊ฝค ์ค๋ ๊ฑธ๋ ธ๋๋ฐ ๋๊ธ ํ๋ฒ์ฉ๋ง ๋ฌ์์ฃผ์๋ฉด ํ์ด ๋ ๊ฑฐ .. 2023. 3. 16. [Swift] ๊ณ ์ฐจ ํจ์ CompactMap ๊ธฐ์กด์ ์ด๋ ์ด์์ ๊ฐ์ ๋ณํ ์์ผ ์๋ก์ด ์ด๋ ์ด๋ฅผ ๋ฐํํ๋ ๊ฒ์ด -> map ์ฌ๊ธฐ์ nil ๊ฐ์ ์ ๊ฑฐํ ๊ฒ์ด compactMap ์ ๋๋ค compactMap์ด ์ด์ ๋ ๋๋ฌด ๋ชธ์ ์ต์ด๋ฒ๋ ธ์ง๋ง.. ์ ๋ฆฌ์ฐจ์์์ ์ค์ฌ๋ก ์ด๋ป๊ฒ ์ฐ์ผ ์ ์์์ง ์ ๋ฆฌํ์ต๋๋ค!! 1. nil ์ ๊ฑฐํ๊ธฐ let test = [1, 2, nil, 4, 5, nil] let removedNilTest = test.compactMap { $0 } [1, 2, 4, 5] CompactMap์ nil์ ์ ์ธ์ํค๊ธฐ ๋๋ฌธ์ ์ต์ ๋์ ์ฌ์ฉํด์ผ ํ๋ ํ๊ฒฝ์์ ํจ๊ณผ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ํธ๋ค๋ง ํ ์ ์์ด์! ๋ง์ฝ nil ๊ฐ์ด ๊ทธ๋๋ก ํ์ํ๋ค๋ฉด map์ ์ฐ๋ฉด ๋ฉ๋๋ค~ let sameWithAbove = test.compactMap { value in return.. 2023. 3. 9. [iOS/Swift] Dynamic Link ์ ๋ฆฌ ๋ก๊ทธ์ธ - Google ๊ณ์ ์ด๋ฉ์ผ ๋๋ ํด๋์ ํ accounts.google.com Firebase > ์ฝ์๋ก ์ด๋ > ํ๋ก์ ํธ ์ ํ > ๋ชจ๋ ์ ํ > Dynamic Links ์์ํ๊ธฐ ๋ฒํผ ์ ํ ์ฌ์ฉํ๊ณ ์ ํ๋ ๋๋ฉ์ธ ํ๋ฆฌํฝ์ค๋ฅผ ์ ๋ ฅํ๋ฉด Google์์ ์ ๊ณตํ๋ ๋๋ฉ์ธ ๋ชฉ๋ก์ด ๋ธ ๊ตฌ๊ธ์์ ์ ๊ณตํ๋ ๋๋ฉ์ธ์ ์ ํํ๊ณ ๊ณ์ ๋ฒํผ์ ๋๋ฆ (๊ตฌ๊ธ์์ ์ ๊ณตํ๋ ๋๋ฉ์ธ์ xxx.page.link) ์ด๋ฏธ ๋ฑ๋ก๋ ์ด๋ฆ์ ์ฌ์ฉ ๋ถ๊ฐ๋ฅ ์ฌ์ฉ๊ฐ๋ฅํ ๋๋ฉ์ธ์ธ ๊ฒฝ์ฐ ์๋ฃ ๋จ๊ณ๋ก ๋์ด๊ฐ ์ ๋์ ๋งํฌ ๋ฒํผ ํด๋ฆญ ๋จ์ถ URL์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฌ์ฉํ ๋งํฌ๋ฅผ ์ง์ ํจ ์์๋ก ์ง์ ๋๋ URL์ ์ฌ์ฉํ๋ฉด ๋จ url ํ๋ฆฌํฝ์ค + ibi์ ๋ฒ๋ค ์์ด๋๋ฅผ ์ ์ด์ค ํธ์ ์ค์ ํ๋ค๋ฉด team ID๊ฐ ๋ฑ๋ก๋์ด ์์ App store id๋ฅผ ์ ๋ ฅํ.. 2023. 3. 8. [iOS/Swift] Firebase Remote Notification ์ ๋ฆฌ Apple Develper Site Setting 1. APNs key ์ค๋น Apple Developer ์ฌ์ดํธ > ์ผ์ชฝ ๋ฉ๋ด > Keys ์ ํ Keys + ๋ฒํผ์ ๋๋ฌ ์๋ก์ด ํค ๋ฑ๋ก Apple Push Notification service ๋ฒํผ์ ๋๋ฅด๊ณ , key name์ ์ง์ Continue ๋ฒํผ์ด ํ์ฑํ ๋๋ฉด ๋๋ฌ ์ค ์ ๋ณด๋ฅผ ํ์ธํ ๋ค Register์ ๋๋ฌ ํค๋ฅผ ๋ฑ๋กํจ 2. Key ID ํ์ธ ์ธ์ฆ ํค์ Key ID ํ์ธ ์ถํ Firebase ์ค์ ์ ํ์ํจ 3. Team ID ํ์ธ apple developer ์ธ์ฆ์, ์๋ณ์ ๋ฐ ํ๋กํ์ผ ๊ด๋ฆฌ ํ์ด์ง์์ ์ค๋ฅธ์ชฝ ์๋จ์ ํ ์์ด๋๊ฐ ๋์ ์์ง๋ง ํด๋น ์ฌ์ดํธ๋ก๋ ํ์ธ ๊ฐ๋ฅ ๋ก๊ทธ์ธ - Apple idmsa.apple.com ๋ก๊ทธ์ธ ํ ์คํฌ๋กค ํ๊ฒ ๋๋ฉด.. 2023. 3. 8. [iOS/Swift] Localization ์ฝ๋๋ก ๋ค๊ตญ์ด ์ฒ๋ฆฌ PROJECT > Info ํญ > Localization ์น์ > + ๋ฒํผ ๋๋ฌ์ ์ธ์ด ์ถ๊ฐ New File > Strings File ์ถ๊ฐ ์์ฑ๋ ํ์ผ ํ์ธ > ์ค๋ฅธ์ชฝ File ์ธ์คํํฐ ํ์ธ Localize ๋ฒํผ > ์ธ์ด ์ ํ > Localize ๋ฒํผ ํด๋ฆญ ๋ค์ File Inspector ํ์ธํ๋ฉด Localization ์น์ ์์ญ์ ์ถ๊ฐํ ์ธ์ด ๋ชฉ๋ก์ด ํ์๋จ ๋ค๊ตญ์ด ์ฒ๋ฆฌํ ์ธ์ด ์ ํํ๋ฉด Project Navigator์์ ์ธ์ด ๋ณ๋ก Localizable ์์ฑ๋ ๊ฒ ํ์ธ ๊ฐ๋ฅ ๋์์ด์์ด, ํ๋ฉด๋ณ๋ก ๋ณ์ญ๋์ด์ผ ํ๋ ๋จ์ด๊ฐ ๋ค๋ฅผ ์ ์์ผ๋ฏ๋ก ํค๊ฐ์ ๊ณ ์ ๊ฐ์ผ๋ก ์์ฑํด ์ฃผ๋ ๊ฒ์ด ์ข์ String Extension extension String { var localized: String { return NSL.. 2023. 2. 23. [iOS/Swift] SafeArea ๋์ด ๊ตฌํ๊ธฐ viewController์ view view.safeAreaInsets.top view.safeAreaInsets.bottom 0.0 0.0 20.0 viewDidLoad, viewWillAppear, viewDidAppear์์ ๊ฐ๊ฐ view์ safeAreaInsets์ผ๋ก ์ ๊ทผํ top์ ๊ฒฐ๊ณผ viewDidAppear์์ ์ ํํ ๊ฐ์ ์ป์ ์ ์์ ๋๋ถ๋ถ UI๋ฅผ viewDidLoad์์ ์ค๋นํ๋ฏ๋ก, viewDidAppear์์ ํ์ํ ์ํฉ์ด ์๋ ๊ฒฝ์ฐ ์ ํํ safeArea์ ๋์ด๋ฅผ ๊ตฌํ๊ธฐ ์ด๋ ค์ UIApplication.shared.windows.first iOS 15.0 ๋ฏธ๋ง ๋ฒ์ ์์ ์ฌ์ฉ๊ฐ๋ฅ UIApplication.shared.windows.first?.safeAreaInsets.top UI.. 2023. 2. 5. [iOS/Swift] UIDevice ๋ฒ์ , UUID, ๊ธฐ๊ธฐ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ UIDevice current ์ธ์คํด์ค๋ก ํ์ฌ ๊ธฐ๊ธฐ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ ์ฌ ์ ์์ ์ด๋ฆ, ๊ธฐ๊ธฐ ๋ชจ๋ธ, ์ด์์ฒด์ ์ด๋ฆ๊ณผ ๋ฒ์ ๋ฑ์ ์ ๋ณด๋ฅผ ์ป์ ๋ ์ฌ์ฉํจ ๋ฌผ๋ฆฌ์ ๋ฐฉํฅ(๊ธฐ๊ธฐ๋ฅผ ๊ฐ๋ก, ์ธ๋ก๋ก ๋๋ ๊ฒ)๊ณผ ๊ฐ์ ๊ธฐ๊ธฐ์ ์ํ ๊ฐ์ ๋ณํ๋ฅผ ์ถ์ ํ๋๋ฐ ์ฌ์ฉํ ์ ์์ ๋ฒ ํฐ๋ฆฌ ์ํ์ ๋ํ ์ ๋ณด์ ๊ทธ ๋ณํ๋ฅผ ์ถ์ ํ ์ ์์ ์ฌ์ฉ์๊ฐ ๊ธฐ๊ธฐ๋ฅผ ์ก๊ณ ์ผ๊ตด์ ๊ฐ๊น์ด ๊ฐ์ ธ๊ฐ๋์ง๋ฅผ ํ์ธ ํ ์ ์๋ ๊ทผ์ ์ผ์์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํจ import UIKit class DeviceInfo { static var sharedObject: DeviceInfo = DeviceInfo() /// Device Name (e.g. "iPhone 14 Pro") public func getDeviceName() -> String? { return U.. 2023. 2. 4. [iOS/Swift] infoDictionary ์ฑ ๋ฒ์ , ๋ฒ๋ค ์์ด๋ ๊ฐ์ ธ์ค๊ธฐ infoDictionary๋ ํค ๊ฐ์ผ๋ก ๊ฐ์ ์ ๊ทผ ํ ์ ์๋ ๋์ ๋๋ฆฌ ํ์ ํ๊ฒ > Info ํญ์ ์๋ Info.plist ํ์ผ๋ก ๋ถํฐ ์์ฑ๋์ด ํด๋น ๊ฐ์ ์ ๊ทผ ํ ์ ์์ infoDictionary์ ํค๊ฐ์ Info.plist์ Raw Keys ์ผ๋ก ์ค์ ํด์ ํ์ธํ ์ ์์ ์ฃผ๋ก CFBundleIdentifier, NSMainNibFile, NSPrincipalClass ํค ๊ฐ์ด ์ฌ์ฉ๋จ ์ฑ ๋ฒ์ ํ์ธ /// App Version public func getCurrentAppVersion() -> String? { guard let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { return .. 2023. 2. 4. ์ด์ 1 2 3 4 5 ยทยทยท 11 ๋ค์