๐ [fix] iCloud ๋๊ธฐํ ์๊ตฌ ์ค๋จ(UC ๋ถ์ฌ ๋ธ๋ฆญ) ์ํ self-heal ๋ณต๊ตฌ ์ถ๊ฐ#182
๐ [fix] iCloud ๋๊ธฐํ ์๊ตฌ ์ค๋จ(UC ๋ถ์ฌ ๋ธ๋ฆญ) ์ํ self-heal ๋ณต๊ตฌ ์ถ๊ฐ#182geeksbaek wants to merge 2 commits into
Conversation
hasEverHadUserCollection=true์ธ๋ฐ UC๊ฐ 0๊ฐ์ธ ์ํ์์ CloudKit re-import๊ฐ UC๋ฅผ ๋๋๋ ค์ฃผ์ง ๋ชปํ๋ฉด(ํด๋ผ์ฐ๋์ UC ์์, iCloud ๋ก๊ทธ์์/์ ํ ๋ฑ) getUserCollection()์ด ์๊ตฌํ .notFound๋ฅผ throwํ์ฌ ๋ชจ๋ ์ ์ฅ/๋๊ธฐํ๊ฐ ์กฐ์ฉํ ์คํจํ๊ณ ์ค์ ํ๋ฉด์ด "iCloud ๋ฐ์ดํฐ ๋๊ธฐ ์ค..."์ ๊ณ ์ ๋๋ ๋ฌธ์ ์์ . - re-import ๊ฐ๋ฅ์ฑ์ด ์๋ค๊ณ ํ๋จ๋๋ฉด ์ UC ์์ฑ ํ์ฉ (self-heal): - import_settled: ์ธ์ ๋ด Import ์ฑ๊ณต + grace period ๊ฒฝ๊ณผ ํ์๋ UC ์์ - no_icloud_account: ๊ณ์ .noAccount/.restricted โ import๊ฐ ์ฌ ์ ์์ - persisted_24h: UC ๋ถ์ฌ 24์๊ฐ ์ง์ ๋ฐฑ์คํฑ (UserDefaults ํ์์คํฌํ) - checkiCloudAccountStatus()์์ lastKnownAccountStatus ์บ์ฑ - Import ์ข ๋ฃ ํ UC๊ฐ ์์ผ๋ฉด grace ๋ง๋ฃ ์งํ Path-B ๊ฐฑ์ ์ฌํธ๋ฆฌ๊ฑฐ (scheduleSelfHealRecheckIfNeeded) โ ์ฌ์ฉ์ ์กฐ์ ์์ด๋ UI ๋ณต๊ตฌ - UC ์ ์ ์กฐํ/์๋์ ์ด๊ธฐํ ์ ๋ถ์ฌ ๊ด์ธก ํ์์คํฌํ ์ ๋ฆฌ - Analytics: sync_uc_created path=self_heal + reason ํ๋ผ๋ฏธํฐ ์ถ๊ฐ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PDsJ57bUdibeuKL5P72y6f
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PDsJ57bUdibeuKL5P72y6f
๐ WalkthroughWalkthroughAdds a "UC missing self-heal" mechanism to CoreDataStorage that detects when a user collection is persistently missing despite having existed before, tracks observation timestamps and account status, schedules a post-import recheck, and creates a new UC when conditions permit. Documentation updated accordingly. ChangesUC Missing Self-Heal
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CloudKit
participant CoreDataStorage
participant UserDefaults
participant NotificationCenter
CloudKit->>CoreDataStorage: didFinishCloudImport
CoreDataStorage->>CoreDataStorage: scheduleSelfHealRecheckIfNeeded()
CoreDataStorage->>NotificationCenter: didReceiveRemoteChanges (after delay)
NotificationCenter->>CoreDataStorage: getUserCollection triggered
CoreDataStorage->>CoreDataStorage: ucMissingSelfHealReason()
CoreDataStorage->>UserDefaults: read/write observation timestamp
alt reason returned
CoreDataStorage->>CoreDataStorage: create new UC (selfHeal path)
else no reason
CoreDataStorage->>UserDefaults: markUCMissingObserved()
CoreDataStorage-->>CoreDataStorage: throw .notFound
end
Possibly related PRs
๐ฅ Pre-merge checks | โ 4 | โ 1โ Failed checks (1 warning)
โ Passed checks (4 passed)
โจ Finishing Touches๐ Generate docstrings
๐งช Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
๐ค Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Animal-Crossing-Wiki/Projects/App/Sources/CoreDataStorage/CoreDataStorage.swift`:
- Around line 190-231: SwiftLint is flagging same-line guard-else returns in the
self-heal helpers, so update the affected `guard` statements in
`markUCMissingObserved`, `clearUCMissingObservation`, and the related
`scheduleSelfHealRecheckIfNeeded` logic to use newline-form `else` blocks that
satisfy `conditional_returns_on_newline`; then run the projectโs SwiftLint
auto-fix flow to apply the formatting consistently.
๐ช Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
โน๏ธ Review info
โ๏ธ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 00ad0540-ea8d-4d11-af16-b93f20b2d686
๐ Files selected for processing (2)
Animal-Crossing-Wiki/Projects/App/Sources/CoreDataStorage/CoreDataStorage.swiftdocs/features/icloud-sync.md
| private func ucMissingSelfHealReason() -> String? { | ||
| // ์ด ์ธ์ ์์ CloudKit Import๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋๋๋ฐ๋ UC๊ฐ ์์. | ||
| // grace period(์ฒซ Import ํ 120์ด)๋ฅผ ์ด๋ฏธ ํต๊ณผํ ๋ค์๋ง ๋๋ฌํ๋ฏ๋ก, | ||
| // ํ์ import batch๋ฅผ ๊ธฐ๋ค๋ฆด ๋งํผ ๊ธฐ๋ค๋ฆฐ ์ํ โ ํด๋ผ์ฐ๋์ ๋ณต์ํ UC๊ฐ ์๋ค๊ณ ํ๋จ. | ||
| if lastSuccessfulImportDate != nil { | ||
| return "import_settled" | ||
| } | ||
| // iCloud ๊ณ์ ์ด ์๊ฑฐ๋ ์ ํ๋จ โ re-import ์์ฒด๊ฐ ์ฌ ์ ์์ผ๋ฏ๋ก ์ฆ์ ํ์ฉ. | ||
| // (๊ณ์ ๋ฏธ๋ก๊ทธ์ธ ์ NSPersistentCloudKitContainer๊ฐ ๋ก์ปฌ ๋ฏธ๋ฌ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๋ | ||
| // ๊ฒฝ์ฐ๊ฐ ์์ด, ์ด ์ผ์ด์ค๋ฅผ ๋ง์ผ๋ฉด ๋น iCloud ์ฌ์ฉ์๋ ์ฑ์ ์์ ์ธ ์ ์๊ฒ ๋จ) | ||
| if let status = lastKnownAccountStatus, status == .noAccount || status == .restricted { | ||
| return "no_icloud_account" | ||
| } | ||
| // ๋ฐฑ์คํฑ: UC ๋ถ์ฌ ์ํ๊ฐ 24์๊ฐ ๋๊ฒ ์ง์ (์คํ๋ผ์ธ ๋ฑ ์ ์กฐ๊ฑด์ผ๋ก ๋ชป ์ก๋ ์ผ์ด์ค) | ||
| let observedAt = UserDefaults.standard.double(forKey: Self.ucMissingFirstObservedAtKey) | ||
| if observedAt > 0 { | ||
| let elapsed = Date().timeIntervalSince1970 - observedAt | ||
| if elapsed > Self.ucMissingSelfHealSeconds { | ||
| return "persisted_24h" | ||
| } | ||
| if elapsed < 0 { | ||
| // ์๊ณ ์ญํ โ ํ์์คํฌํ ์ฌ๊ธฐ๋ก | ||
| markUCMissingObserved(force: true) | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| /// UC ๋ถ์ฌ ์ํ๋ฅผ ์ฒ์ ๊ด์ธกํ ์๊ฐ์ ๊ธฐ๋ก (24์๊ฐ ๋ฐฑ์คํฑ ํ์ ์ฉ, ์ต์ด 1ํ๋ง) | ||
| private func markUCMissingObserved(force: Bool = false) { | ||
| let defaults = UserDefaults.standard | ||
| guard force || defaults.double(forKey: Self.ucMissingFirstObservedAtKey) <= 0 else { return } | ||
| defaults.set(Date().timeIntervalSince1970, forKey: Self.ucMissingFirstObservedAtKey) | ||
| } | ||
|
|
||
| /// UC๊ฐ ์ ์์ ์ผ๋ก ์กฐํ๋๋ฉด ๋ถ์ฌ ๊ด์ธก ๊ธฐ๋ก์ ์ ๋ฆฌ | ||
| private func clearUCMissingObservation() { | ||
| let defaults = UserDefaults.standard | ||
| guard defaults.object(forKey: Self.ucMissingFirstObservedAtKey) != nil else { return } | ||
| defaults.removeObject(forKey: Self.ucMissingFirstObservedAtKey) | ||
| } | ||
|
|
There was a problem hiding this comment.
๐ Maintainability & Code Quality | ๐ก Minor | โก Quick win
Self-heal decision logic looks correct. Backward clock-skew is re-recorded, and each reason gates cleanly before the .notFound fallthrough.
Minor: SwiftLint conditional_returns_on_newline flags the same-line guard โฆ else { return } on Line 221 and Line 228 (and also Line 514/516/518 in scheduleSelfHealRecheckIfNeeded). These are auto-fixable via swiftlint --config .swiftlint.yml --fix.
As per coding guidelines ("SwiftLint ์ค์ ์ ๋ฐ๋ผ ๋ฆฐํธ ๊ฒ์ฌ๋ฅผ ์ํํ๊ณ , ์๋ ์์ ๊ฐ๋ฅํ ๋ฌธ์ ๋ swiftlint --config .swiftlint.yml --fix๋ก ์ฒ๋ฆฌ").
๐งฐ Tools
๐ช SwiftLint (0.65.0)
[Warning] 221-221: Conditional statements should always return on the next line
(conditional_returns_on_newline)
[Warning] 228-228: Conditional statements should always return on the next line
(conditional_returns_on_newline)
๐ค Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@Animal-Crossing-Wiki/Projects/App/Sources/CoreDataStorage/CoreDataStorage.swift`
around lines 190 - 231, SwiftLint is flagging same-line guard-else returns in
the self-heal helpers, so update the affected `guard` statements in
`markUCMissingObserved`, `clearUCMissingObservation`, and the related
`scheduleSelfHealRecheckIfNeeded` logic to use newline-form `else` blocks that
satisfy `conditional_returns_on_newline`; then run the projectโs SwiftLint
auto-fix flow to apply the formatting consistently.
Sources: Coding guidelines, Linters/SAST tools
hasEverHadUserCollection=true์ธ๋ฐ UC๊ฐ 0๊ฐ์ธ ์ํ์์ CloudKit re-import๊ฐ
UC๋ฅผ ๋๋๋ ค์ฃผ์ง ๋ชปํ๋ฉด(ํด๋ผ์ฐ๋์ UC ์์, iCloud ๋ก๊ทธ์์/์ ํ ๋ฑ)
getUserCollection()์ด ์๊ตฌํ .notFound๋ฅผ throwํ์ฌ ๋ชจ๋ ์ ์ฅ/๋๊ธฐํ๊ฐ
์กฐ์ฉํ ์คํจํ๊ณ ์ค์ ํ๋ฉด์ด "iCloud ๋ฐ์ดํฐ ๋๊ธฐ ์ค..."์ ๊ณ ์ ๋๋ ๋ฌธ์ ์์ .
(scheduleSelfHealRecheckIfNeeded) โ ์ฌ์ฉ์ ์กฐ์ ์์ด๋ UI ๋ณต๊ตฌ
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01PDsJ57bUdibeuKL5P72y6f
Summary by CodeRabbit