- ๊ฐ๋ฐ ์ดํฐ๋ ์ด์ : ๊ณต์์ฐ์ , ๊ฐ๋ฐ์ด์ ์ ๋ฆฌ
- ์ ๋ฐ์ดํธ ์ดํฐ๋ ์ด์ : ๊ณต์์ฐ์
Realm
AutoLayout
Snapkit
Alamofire
SwiftyJSON
MVC
Github Action
- ์ฝ 1์ฃผ์ผ ~ 2์ฃผ์ผ ๋์ ๊พธ์คํ ๋ ์ด์์์ ์กฐ์ ํด๋ดค์ต๋๋ค. ์์๊ฐ์ด ์๋ ๋น์จ์ ๊ธฐ์ค์ผ๋ก ์กฐ์ ํ๋ ๊ฒ์ด ์๊ฐ์ ์ธ ์ธก๋ฉด, ๊ฐ๋ฐ ์๋ ์ธก๋ฉด์์ ๋ ํจ์จ์ด ์ข์๊ณ ํ๋ฐ๋ถ ์์ ์์๋ ๋๋ถ๋ถ ๋น์จ์ ์ด์ฉํด ๋ ์ด์์์ ๋ง๋ค์์ต๋๋ค.
-
์ ์ ๊ฐ ์ ์ฅํ ๋จ์ด๋ฅผ ๊ธฐ๋กํ๊ธฐ ์ํด Realm์ ์ ํํ์ต๋๋ค.
-
๊ฐ๋ฐ์ด์: ๊ธฐ์กด์ ์คํค๋ง์์ ๋ ์ง ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์์ ์์๋ก ๋ฃ์ด๋๋ Date()๊ฐ์ ์๋ก์ด Object๋ก ๋ณํํด์ผํ์ต๋๋ค. Realm์ ์คํค๋ง๋ฅผ ๋ณ๊ฒฝํด์ผ ๋๋ค๋ ๊ฒ ์ฆ, ๋ง์ด๊ทธ๋ ์ด์ ์ ํ ์ ์๋ค๋ ๊ฒ์ ์์๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ ์ฉํจ์ผ๋ก์จ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
//Realm migration let config = Realm.Configuration( schemaVersion: 2, migrationBlock: { migration,oldSchemaVersion in if (oldSchemaVersion < 2){ migration.enumerateObjects(ofType: DefineWordModel.className()) { oldObject, newObject in //๊ธฐ์กด์ ๋ ์ง๋ค์ ๋ณํํ๊ณ storedDate์ ๊ฐ์ ๋จ๊ธด๋ค. let format = DateFormatter() format.dateFormat = "yyyy๋ MM์ dd์ผ" let value = format.string(from: oldObject?["date"] as! Date) newObject?["storedDate"] = value } } } )
- API ํต์ ์ ์ํด Alamofire๋ฅผ, ๋ฐ์์จ Json ํํ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด SwiftyJSON์ ํ์ต ๋ฐ ์ ์ฉํ์ฌ ๋๋ค์ผ๋ก ๋์จ ๋จ์ด์ ์ ์๋ฅผ ๋ณด์ฌ์ค ์ ์์์ต๋๋ค.
-
์ถ์ฒ ๋จ์ด ๊ธฐ๋ฅ์ ๋ง๋ค๊ธฐ ์ํด ์ฐ๋ฆฌ๋ง์API๋ฅผ ์ด์ฉํ์ต๋๋ค.
-
์ด๊ธฐ, ์ ์ ์ ๋คํธ์ํฌ ์ํ๋ฅผ ๊ณ ๋ คํ์ง ์๊ณ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ ๋ฐ๊ฒฌํ๊ณ ์ํ๋ ViewController์ ์ง์ ์ Network ์ํ๋ฅผ ํ์ธํ ์ ์๊ฒ ํจ์๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ์ต๋๋ค.
import Network //๋คํธ์ํฌ ์ํ ๋ชจ๋ํฐ func monitorNetwork(){ let monitor = NWPathMonitor() monitor.pathUpdateHandler = { path in if path.status == .satisfied { DispatchQueue.main.async { return } } else { DispatchQueue.main.async { self.showAlert(title: "๋คํธ์ํฌ์ ์ฐ๊ฒฐ๋์ด ์์ง ์์์.\n์ค์ ํ๋ฉด์ผ๋ก ์ด๋ํฉ๋๋ค ๐ฅฒ",connection: true) } } } let queue = DispatchQueue(label: "Network") monitor.start(queue: queue) }
- ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ณ ๋ฐฐํฌํ๋ ์ผ๋ จ์ ๊ณผ์ ์ ๊ฒฝํํ ์ ์์์ต๋๋ค.
- ์ ๋ฐ์ดํธ๋ฅผ ๊พธ์คํ ์งํํ๊ณ ์์ต๋๋ค. ( ๊ฐ์ฅ ์ต๊ทผ ์ ๋ฐ์ดํธ : 2022.3.14 )
ํ์ต ๋ด์ฉ ์ ๋ฆฌ
- CI / CD Github Action
-
Github Action์ด๋
- Pull Request, Push ๋ฑ์ ์ด๋ฒคํธ ๋ฐ์์ ๋ฐ๋ผ ์๋ํ๋ ์์ ์ ์งํํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ
- CI / CD
- ๋ก์ปฌ ๋ ํฌ์งํ ๋ฆฌ์์ ์๊ฒฉ ๋ ํฌ์งํ ๋ฆฌ๋ก ํธ์ฌํ๊ณ ๋ ํ, Github Actions์์๋ ์ด๋ฒคํธ ๋ฐ์์ ๋ฐ๋ผ ์๋์ผ๋ก ๋น๋ ๋ฐ ๋ฐฐํฌํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํ์์ผ์ฃผ๋ ๊ฒ
- Testing
- Pull Request๋ฅผ ๋ณด๋ด๋ฉด ์๋์ผ๋ก ํ ์คํธ๋ฅผ ์งํํ๋ ๊ฒ ๋ํ ๊ตฌํ ๊ฐ๋ฅํ๊ณ ์๋์ผ๋ก Pull Request๋ฅผ open ๋ฐ closeํ ์ ์๊ฒ ๋จ
- Cron Job
- ํน์ ํ ์๊ฐ๋์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฐ๋ณต ์คํํ ์ ์์
-
Github Action์ ๊ตฌ์ฑ์์
-
Workflow
-
Event
- Workflow๋ฅผ ์คํ์ํค๋ ํน์ ํ๋ ( Push, Pull Request, Commit ๋ฑ )์ ์๋ฏธ ํจ
-
Job
- Job์ด๋ ๋์ผํ Runner์์ ์งํ๋๋ Step์ ์งํฉ
- ํ๋์ workflow ๋ด์ ์ฌ๋ฌ Job์ ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋๋ ํ์์ ๋ฐ๋ผ ์์กด ๊ด๊ณ๋ฅผ ์ค์ ํ์ฌ ์์๋ฅผ ์ง์ ํ ์ ์์
- ๊ฐ๋ น Test ์์ ๊ณผ Build ์์ ์ ์ํํ๋ Job๋ค์ด ํ๋์ workflow์ ์กด์ฌํ๋ค๋ฉด Build ์ดํ์ Test๊ฐ ์งํ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ Build Job์ด ๋ง๋ฌด๋ฆฌ ๋ ํ Test Job์ ์คํํ ์ ์๋๋ก ์ง์ ๊ฐ๋ฅ ( Build ์คํจ์ Test๋ ์คํํ์ง ์์ )
-
Step
- ์ปค๋งจ๋๋ฅผ ์คํํ ์ ์๋ ๊ฐ๊ฐ์ Task๋ฅผ ์๋ฏธํ๊ณ , Shell ์ปค๋งจ๋๊ฐ ๋ ์๋ ์๊ณ , ํ๋์ Action์ด ๋ ์๋ ์์
- ํ๋์ Job ๋ด์์ ๊ฐ๊ฐ์ Step์ ๋ค์ํ Task๋ก ์ธํด ์์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์์
-
Action
- Job์ ๋ง๋ค๊ธฐ ์ํด Step์ ๊ฒฐํฉํ ์ปค๋งจ๋๋ก ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ Workflow์ ๊ฐ์ฅ ์์ ๋จ์
- ์ง์ ๋ง๋ค๊ฑฐ๋ Github Community์ ์ํด ์์ฑ๋ Action์ ๋ถ๋ฌ์ ์ฌ์ฉํ ์ ์์
-
Runner
- Runner๋ Github Actions Workflow ๋ด์ ์๋ Job์ ์คํ์ํค๊ธฐ ์ํ ์ ํ๋ฆฌ์ผ์ด์
- Runner Application์ Github์์ ํธ์คํ ํ๋ ๊ฐ์ํ๊ฒฝ ํน์ ์ง์ ํธ์คํ ํ๋ ๊ฐ์ ํ๊ฒฝ์์ ์คํ ๊ฐ๋ฅํ๋ฉฐ Github์์ ํธ์คํ ํ๋ ๊ฐ์ ์ธ์คํด์ค์ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ ๋ฐ ์ฉ๋ ์ ํ์ด ์กด์ฌ
-
-
Workflow ์์ฑ ๋ฐ ํ์ผ ์ค๋ช
-
.github/workflows ๋๋ ํ ๋ฆฌ ๋ด์ .yml ํ์ผ์ ์์ฑํด๋ ๋์ง๋ง, Repository์ Actions ํญ์์ ์๋์ผ๋ก template๋ฅผ ๋ง๋ค์ด์ฃผ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์
-
Github์์ ์ ๊ณตํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ Template๋ set up a workflow yourself๋ฅผ ํด๋ฆญ
-
๋ค์๊ณผ ๊ฐ์ ์์์ .yml ํ์ผ์ด ์์ฑ๋จ
-
์ค๋ช
# Actions ํญ์ ํ์๋ Workflow ์ด๋ฆ name: CI # Workflow๋ฅผ ์คํ์ํค๊ธฐ ์ํ Event ๋ชฉ๋ก on: # ํธ๋ฆฌ๊ฑฐ # ํ๋จ ์ฝ๋์ ๋ฐ๋ผ develop ๋ธ๋์น์ Push ๋๋ Pull Request ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์ Workflow๊ฐ ์คํ push: branches: [main] # ํน์ ํ Branch์ ํธ์ฌ๋์์ ๋ ์ฌ์ฉํ๋ ค๋ฉด ๊ฐ๋ น feature/*๋ก ์์ฑํ๋ฉด ๋จ pull_request: branches: [main] # ํด๋น ์ต์ ์ ํตํด Actions ํญ์์ Workflow๋ฅผ ์คํ workflow_dispatch: # Workflow์ ํ๋ ์ด์์ Job jobs: # Job ์ด๋ฆ์ผ๋ก, build๋ผ๋ ์ด๋ฆ์ผ๋ก Job์ด ํ์ build: # Runner๊ฐ ์คํ๋๋ ํ๊ฒฝ์ ์ ์ runs-on: macos-latest # build Job ๋ด์ step ๋ชฉ๋ก steps: # uses ํค์๋๋ฅผ ํตํด Action์ ๋ถ๋ฌ์ด # ์ฌ๊ธฐ์์๋ ํด๋น ๋ ํฌ์งํ ๋ฆฌ๋ก check-out ๋ฐ ๋ ํฌ์งํ ๋ฆฌ์ ์ ๊ทผํ ์ ์๋ Action์ ๋ถ๋ฌ์ด. - uses: actions/checkout@v2 # ์คํ๋๋ ์ปค๋งจ๋์ ๋ํ ์ค๋ช ์ผ๋ก, Workflow์ ํ์ - name: Build run: echo Hello, world! # ํ๋์ ์ปค๋งจ๋๊ฐ ์๋ ์ฌ๋ฌ ์ปค๋งจ๋๋ ์คํ ๊ฐ๋ฅ - name: Run tests run: | xcodebuild test -project "$XC_PROJECT" -scheme "$XC_SCHEME" -destination 'platform=iOS Simulator,name=iPhone 13'
-
Start Commit ํ Action ํญ์ ํ์ธํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ ์์ ์ผ๋ก ์๋ํ ๊ฒ์ ํ์ธํ ์ ์์.
-
-
Github Action ๋ฐฉ๋ฒ ๋ฐ ์ ์ฉ
-
์ฐธ๊ณ : naljin๋์ ๋ธ๋ก๊ทธ
-
์ ์ฉ๋ฐฉ๋ฒ
name: TID Automation release on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: macos-latest env: # ๊ฐ์ํ๊ฒฝ # Xcode ๋ฒ์ ๋ฐ ํ๋ก์ ํธ์ ์คํค๋ง ์ค์ + ์ฌ์ฉํ ํค์ฒด์ธ ์ค์ ( ์คํฌ๋ฆฝํธ์์ ๋ง๋ค์ด์ ๋ฃ์ ๋ณ์ ) XC_VERSION: ${{ '13.1' }} XC_PROJECT: ${{ 'usket_TID.xcodeproj' }} XC_SCHEME: ${{ 'usket_TID' }} KEYCHAIN: ${{ 'usket.keychain' }} # ๋ฃจํธ PROJECT_ROOT_PATH: ${{ 'usket_TID' }} ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/GithubActionKey.p12.gpg' }} # ์ด๋์ ๋ณตํธํ ํ ๊ฒ์ธ์ง ๋ช ์ DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/GithubActionKey.p12' }} ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/GithubAction.mobileprovision.gpg' }} # ์ด๋์ ๋ณตํธํ ํ ๊ฒ์ธ์ง ๋ช ์ DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/GithubAction.mobileprovision' }} # ๊ธฐ์กด์ secrets๋ฅผ ๊ฐ์ง๊ณ ์์ ์ ์ฉ CERTS_EXPORT_PWD: ${{ secrets.CERTS_EXPORT_PWD }} CERTS_ENCRYPTION_PWD: ${{ secrets.CERTS_ENCRYPTO_PWD }} PROFILES_ENCRYPTO_PWD: ${{ secrets.PROFILES_ENCRYPTO_PWD }} # ์์นด์ด๋ธ path ๋ฐ ์ฑ์คํ ์ด์ ์ฌ๋ฆด artifacts path ์ค์ XC_ARCHIVE_PATH: ${{ 'usket_TID.xcarchive' }} XC_EXPORT_PATH: ${{ './artifacts' }} steps: - name: Select Xcode Version run: "sudo xcode-select -s /Applications/Xcode_$XC_VERSION.app" - uses: actions/checkout@v3 - name: Build run: echo Hello, world! # ์์์ ๋ง๋ค์ด๋ ํค์ฒด์ธ ์ ์ฉ - name: Configure Keychain run: | security create-keychain -p "" "$KEYCHAIN" security list-keychains -s "$KEYCHAIN" security default-keychain -s "$KEYCHAIN" security unlock-keychain -p "" "$KEYCHAIN" # Code Signing ์คํ - name : Configure Code Signing run: | gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERTS_ENCRYPTION_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROFILES_ENCRYPTO_PWD" "$ENCRYPTED_PROVISION_FILE_PATH" security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_EXPORT_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN" mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` # ํ๋กํ์ผ๋ค์ renameํ๊ณ ์๋ก๋ง๋ ๋๋ ํ ๋ฆฌ์ ๋ณต์ฌ for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done # ์์นด์ด๋ธ! - name: Archive working-directory: usket_TID run: | mkdir artifacts xcodebuild archive -project "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration release -archivePath "$XC_ARCHIVE_PATH" # App Store๋ก ๋ด๋ณด๋ด๊ธฐ - name: Export for App Store run: | xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XC_EXPORT_PATH" # ์ ๋ก๋ํ๋ฉด ๋! - name: Upload Artifact uses: actions/upload-artifact@v3 with: name: Artifacts path: ./artifacts
-
Artifact๊ฐ ์๋ TestFlight๋ก ์ ์ฉ๋ฐฉ๋ฒ
-
๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์ ์๋ค๋ ์ค๋ฅ ์ค๋ฅ
- apple-actions/upload-testflight-build@v1๋ฅผ ์ด์ฉํ์ ๊ฒฝ์ฐ ๋ฐ์ํจ.
- ๋๋ ํ ๋ฆฌ์ ํ์ผ์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ณ๊ฒฝ
-
์๋ ์ ์ฉ ํ์ด์ผํ๋ ๋ฐฉ๋ฒ
name: Upload app to TestFlight uses: apple-actions/upload-testflight-build@v1 with: app-path: 'usket_TID.ipa' issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }} api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }} api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}
-
๋ค์๊ณผ ๊ฐ์ด ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑ ๋ฐ base64๋ก ์ธ์ฝ๋ฉ๋ Private Key๋ฅผ decodingํ์ฌ ๋ฃ์ ํ ์คํ ๊ทธ๋ฆฌ๊ณ ์ฑ๊ณต!
name: TID Automation release on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: macos-latest env: # ๊ฐ์ํ๊ฒฝ XC_VERSION: ${{ '13.1' }} XC_PROJECT: ${{ 'usket_TID.xcodeproj' }} XC_SCHEME: ${{ 'usket_TID' }} XC_ARCHIVE_PATH: ${{ 'usket_TID.xcarchive' }} KEYCHAIN: ${{ 'usket.keychain' }} ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/GithubActionKey.p12.gpg' }} DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/GithubActionKey.p12' }} # ์ด๋์ ๋ณตํธํ ํ ๊ฒ์ธ์ง ๋ช ์ ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/GithubAction.mobileprovision.gpg' }} DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/GithubAction.mobileprovision' }} # ์ด๋์ ๋ณตํธํ ํ ๊ฒ์ธ์ง ๋ช ์ CERTS_EXPORT_PWD: ${{ secrets.CERTS_EXPORT_PWD }} CERTS_ENCRYPTION_PWD: ${{ secrets.CERTS_ENCRYPTO_PWD }} PROFILES_ENCRYPTO_PWD: ${{ secrets.PROFILES_ENCRYPTO_PWD }} steps: - name: Setting checkout uses: actions/checkout@v3 - name: Select Xcode Version run: "sudo xcode-select -s /Applications/Xcode_$XC_VERSION.app" - name: Configure Keychain run: | security create-keychain -p "" "$KEYCHAIN" security list-keychains -s "$KEYCHAIN" security default-keychain -s "$KEYCHAIN" security unlock-keychain -p "" "$KEYCHAIN" security set-keychain-settings -lut 1200 security list-keychains - name : Configure Code Signing run: | gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERTS_ENCRYPTION_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROFILES_ENCRYPTO_PWD" "$ENCRYPTED_PROVISION_FILE_PATH" security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_EXPORT_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN" mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` # ํ๋กํ์ผ๋ค์ renameํ๊ณ ์๋ก๋ง๋ ๋๋ ํ ๋ฆฌ์ ๋ณต์ฌ for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done - name: Archive App working-directory: usket_TID run: | xcodebuild clean archive -project "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration release -archivePath "$XC_ARCHIVE_PATH" - name: Export App working-directory: usket_TID run: | xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath . -allowProvisioningUpdates ls # Make Private API Key Path - name: Install private API key P8 env: APPSTORE_API_PRIVATE_KEY: ${{ secrets.APPSTORE_API_PRIVATE_KEY }} APPSTORE_API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }} # Decode Private Key run: | mkdir -p ~/private_keys echo -n "$APPSTORE_API_PRIVATE_KEY" | base64 --decode --output ~/private_keys/AuthKey_$APPSTORE_API_KEY_ID.p8 ls - name: Upload app to TestFlight env: APPSTORE_API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }} run: | cd usket_TID ls xcrun altool --output-format xml --upload-app -f usket_TID.ipa -t ios --apiKey $APPSTORE_API_KEY_ID --apiIssuer ${{ secrets.APPSTORE_ISSUER_ID }}
-
๋ฒ์ | ์ ๋ฐ์ดํธ ๋ด์ญ | ์ค๋ช |
---|---|---|
v2.12 | Localize | ๋ค๊ตญ์ด ์ฒ๋ฆฌ(English) [ ๋ค๊ตญ์ด์ฒ๋ฆฌ ๋ฐฉ๋ฒ ๊ธฐ๋ก ] |
v2.11 | ์๋ฆผ ์ค์ ์ ์๋ฆผ์ด ์ค์ง ์๋ ์ค๋ฅ | TimeZone ์ด์๋ก ์ธํ ์๋ฆผ์ด ์ด์ ๋ ์ง์ ๋ฑ๋ก๋๋ ์ด์๋ฅผ ํด๊ฒฐํ์ต๋๋ค. |
v2.10 | Calendar์์ ๋จ์ด ํด๋ฆญ ์ด๋ฒคํธ | ์์ ํ์ด์ง๋ก ์ด๋๊ฐ๋ฅํ๊ฒ ๋ณ๊ฒฝํ์ต๋๋ค. |
v2.08 | CI / CD [ CI/CD ๊ธฐ๋ก(1) - ๋ธ๋ก๊ทธ ] [ CI/CD ๊ธฐ๋ก(2) - ๋ธ๋ก๊ทธ ] [ CI/CD ๊ธฐ๋ก(3) - ๋ธ๋ก๊ทธ ] |
Github Action์ ์ด์ฉํด ์๋๋ฐฐํฌ ํ๊ฒฝ์ ๊ตฌ์ถํ์ต๋๋ค. |
v2.07 | ์ถ๊ฐ๋ฒํผ ํด๋ฆญ์ Navigation Bar๋ Ove lay View์ ๊ฐ์ธ์ง์ง ์๋ ์ค๋ฅ [ ํธ๋ฌ๋ธ ์ํ ๊ธฐ๋ก - ๋ธ๋ก๊ทธ ] |
ํด๋น ์ค๋ฅ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. |
v2.06 | ๊ฐ๋ฐ, ์ฑ, ๋ฆฌ๋ทฐ๋ฅผ ์ํ ๋ฒํผ ์์ฑ | ๊ฐ๊ฐ ๊นํ๋ธ ๋งํฌ, ์ฑ๊ด๋ จ ๋ฌธ์๋ฅผ ์ํ ์ด๋ฉ์ผ ๋ฅ๋งํฌ, ๋ฆฌ๋ทฐํ์ด์ง๋ก ์ด๋๊ฐ๋ฅํ ๋ฒํผ์ ์ถ๊ฐ |
v2.05 | ๋ก๊ณ ๋์์ด๋ ์ธ์คํ๊ทธ๋จ ๋งํฌ | ์์ฒญ์ผ๋ก ๋งํฌ๋ฅผ ์ฒจ๋ถ ๋ฐ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ปฌ๋ฌ |
v2.04 | Firebase Crashlytics | Firebase Crashlytics ์ ์ฉ ๋ฐ ๊ธฐํ ์ค๋ฅ์์ |
v2.03 | Local Notification [ ํธ๋ฌ๋ธ ์ํ ๊ธฐ๋ก - ๋ธ๋ก๊ทธ ] |
๋ก์ปฌ์๋ฆผ์ ํ ๋จ์ด๋ง ๋ฐ๋ณตํด์ ์ค๋ ์ด์๋ฅผ ์์ ํ์ต๋๋ค. |
v2.02 | ๋ ์ด์์ ๋ฒ๊ทธ ์์ | ๋จ์ด์ ๋ป์ ๋ณด์ฌ์ฃผ๋ TableView์์ ๋ฐ์ํ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ์ต๋๋ค. |
v2.01 | ํต๊ณ ๋ฒ๊ทธ ์์ | ์์ด ๋ฐ๋๊ฒ ๋ ๊ฒฝ์ฐ ๊ธฐ์กด์ ์ฝ๋์์ nil ์ฒ๋ฆฌ๋ก ์ธํ ์ค๋ฅ๊ฐ ์กด์ฌ, ์ด๋ฅผ ํด๊ฒฐํ์ต๋๋ค. |
v2.0 | ๋ ์ด์์ ๋ฒ๊ทธ ์์ , ์ ์ฅ์ ํ ์คํธ ์๋ฆผ ์ถ๊ฐ, ์์ฑํ์ด์ง ์ง์ ์ ์ ์ค์ฒ๋ก ๋๊ฐ๊ธฐ ์ถ๊ฐ, ์์ ์ ๊ฐ์ ๊ณผ ์ ์ ๋ถ๋ถ๊น์ง ๋ณด์ด๊ฒ ์ถ๊ฐ, ํต๊ณ์์น ์์ , ๋ก์ปฌ ์๋ฆผ ์ ๊ณต, ์บ๋ฆฐ๋ ์ ๊ณต | ์ถ์ ์ดํ ๋ฐ์ ํผ๋๋ฐฑ ํตํด ์บ๋ฆฐ๋์ ์๋ฆผ์ ์ค์ ์ผ๋ก ์ ๋ฐ์ดํธ๋ฅผ ์งํํ์ต๋๋ค. |
-
SnapKit
- ๋ ์ด์์์ ๊ดํด ๊ฒ์์ ํ๋ค๋ณด๋ฉด SnapKit์ ๋ํ ๋ต๋ณ๋ค์ด ๋ง์ด ๋ณด์์ต๋๋ค. ์ฝ๋๋ฅผ ์ด์ฉํ์ฌ ๋ ์ด์์์ ์ก์ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ ๊ฒ์ ์๊ฒ ๋์๊ณ ๊ฐ๋จํ ๋ทฐ๋ค ๊ฐ์ ๊ฒฝ์ฐ์๋ ์ฝ๋๋ฅผ ํ์ฉํด ๋ง๋ ๋ค๋ฉด ๊ฐ๋ฐ์๊ฐ ์ธก๋ฉด์์ ๋์ ํ์ฉ๋๊ฐ ์๋ค๊ณ ์๊ฐ์ด ๋ค์๊ณ ๋ค์ ํ๋ก์ ํธ์๋ ์ด๋ฅผ ์ ๊ทน์ ์ผ๋ก ํ์ฉํด ๋ณด๊ณ ์ถ์ด์ก์ต๋๋ค.
-
MVVM
- ๊ธฐ์กด์ MVC ๋์์ธ ํจํด์ ํ์ฉํ์ฌ ๊ฐ๋ฐ์ ํ์ง๋ง ViewController์ UI + ๊ธฐ๋ฅ์ ๋ชจ๋ ๋ฃ์ด์ผํ๊ธฐ์ ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๋ค๊ณ ์๊ฐ์ด ๋ค์์ต๋๋ค. ๊ฐ๋
์ฑ์ ๋์ด๊ณ ํจ์จ์ ์ธ ๊ด๋ฆฌ๋ฅผ ์ํด MVVM ๋์์ธ ํจํด์ ํ์ตํด์ผ ๊ฒ ๋ค๊ณ ๋ค์งํ์ต๋๋ค.
- ๊ธฐ์กด์ MVC ๋์์ธ ํจํด์ ํ์ฉํ์ฌ ๊ฐ๋ฐ์ ํ์ง๋ง ViewController์ UI + ๊ธฐ๋ฅ์ ๋ชจ๋ ๋ฃ์ด์ผํ๊ธฐ์ ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๋ค๊ณ ์๊ฐ์ด ๋ค์์ต๋๋ค. ๊ฐ๋
์ฑ์ ๋์ด๊ณ ํจ์จ์ ์ธ ๊ด๋ฆฌ๋ฅผ ์ํด MVVM ๋์์ธ ํจํด์ ํ์ตํด์ผ ๊ฒ ๋ค๊ณ ๋ค์งํ์ต๋๋ค.