Conversation
📝 WalkthroughWalkthrough앱 아이콘을 기기별 명시 항목으로 교체하고 스플래시를 정적 이미지에서 Lottie 애니메이션으로 전환하며, lottie-ios SPM 추가 및 관련 프로젝트 파일과 Lottie 래퍼·리소스가 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant App as 앱 런치
participant Splash as SplashView
participant Lottie as LottieView/LottieAnimationView
participant UD as UserDefaults
participant Router as Router/네비게이터
App->>Splash: 스플래시 화면 표시
Splash->>Lottie: LottieView(animationName:"splash") 생성·재생
Lottie-->>Splash: 애니메이션 재생(또는 루프/플레이완료)
Splash->>UD: 사용자 상태 조회 (userId, onboarding 등)
UD-->>Splash: 상태 반환
Splash->>Router: navigateBasedOnUserStatus() 호출 → 화면 전환
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Onboarding/SplashView.swift (1)
35-38: 재진입 시 중복 네비게이션 방지 필요onAppear가 여러 번 호출되면 지연 작업이 중복 등록될 수 있습니다. 재등장/백그라운드 복귀 시 중복 네비게이션을 막는 가드/취소 로직을 추가해 주세요.
🛠️ 제안 수정
struct SplashView: View { `@EnvironmentObject` private var appCoordinator: AppCoordinator private let userDefaultService: UserDefaultService + `@State` private var navigationWorkItem: DispatchWorkItem? @@ - .onAppear { - DispatchQueue.main.asyncAfter(deadline: .now() + 3) { - navigateBasedOnUserStatus() - } - } + .onAppear { + guard navigationWorkItem == nil else { return } + let workItem = DispatchWorkItem { navigateBasedOnUserStatus() } + navigationWorkItem = workItem + DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: workItem) + } + .onDisappear { + navigationWorkItem?.cancel() + navigationWorkItem = nil + }
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved`:
- Around line 13-20: The project is using lottie-ios version "4.6.0" (identity
"lottie-ios") which requires Swift 6.0+, while the project SWIFT_VERSION is set
to 5.0; either update the project Swift setting or pin a compatible lottie
version: change the build setting SWIFT_VERSION to "6.0" in your Xcode project
targets (or workspace build settings) and regenerate packages, or update the
"state.version" for identity "lottie-ios" in Package.resolved to a lower
lottie-ios release that supports Swift 5.x and then run SwiftPM update to ensure
the lockfile and dependencies are consistent.
In `@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Lottie`+.swift:
- Around line 15-35: makeUIView currently creates a new LottieAnimationView but
updateUIView is empty, so changes to animationName or loopMode aren’t applied;
implement the Coordinator pattern to store a persistent reference (e.g.,
coordinator.animationView) when creating the view in makeUIView, assign the
created LottieAnimationView to that coordinator property, and then implement
updateUIView to compare and update the coordinator.animationView: if
animationName changed load/set the new LottieAnimationView animation, update
loopMode, and restart/play as needed so parameter changes are reflected without
recreating the whole SwiftUI view.
♻️ Duplicate comments (1)
Cherrish-iOS/Cherrish-iOS.xcodeproj/project.pbxproj (1)
385-405: Lottie 패키지 참조 추가 확인SPM 연결은 적절해 보이나, 4.6.0의 호환성/라이선스 확인이 필요합니다(앞선 Package.resolved 코멘트와 동일한 확인 항목).
| { | ||
| "identity" : "lottie-ios", | ||
| "kind" : "remoteSourceControl", | ||
| "location" : "https://github.com/airbnb/lottie-ios", | ||
| "state" : { | ||
| "revision" : "0cb03fd7564d27345bcd96144b811e56212949c6", | ||
| "version" : "4.6.0" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
lottie-ios 4.6.0 minimum iOS version Swift support requirements
💡 Result:
- Minimum iOS deployment target: iOS 13.0+. [1][2]
- Swift / Xcode requirement for lottie-ios 4.6.0: Xcode 16 / Swift 6.0 or later. [1]
Sources:
[1] lottie-ios 4.6.0 release notes.
[2] Issue/notes reporting lottie-ios raised minimum deployment to iOS 13.0 (4.4.x → 13.0).
🌐 Web query:
lottie-ios license Apache MIT
💡 Result:
- airbnb/lottie-ios (the native iOS library) is licensed under Apache License 2.0. [1]
- airbnb/lottie-web is licensed under the MIT License. [2]
- LottieFiles' dotlottie-ios (a separate .lottie player) is MIT. [3]
If you need the exact license text, check each repo's LICENSE file linked above.
Sources: [1] GitHub — airbnb/lottie-ios (Apache-2.0). [2] GitHub — airbnb/lottie-web (MIT). [3] GitHub — LottieFiles/dotlottie-ios (MIT).
🏁 Script executed:
find . -name "project.pbxproj" -o -name "*.swift" -o -name "project.yml" | head -20Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1378
🏁 Script executed:
cd Cherrish-iOS && cat -n Cherrish-iOS.xcodeproj/project.pbxproj | grep -i "iphoneos" | head -20Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 745
🏁 Script executed:
cd Cherrish-iOS && cat -n Cherrish-iOS.xcodeproj/project.pbxproj | grep -i "swift" | head -20Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1239
lottie-ios 4.6.0 Swift 버전 호환성 문제
lottie-ios 4.6.0은 Swift 6.0 이상이 필요하지만, 프로젝트의 SWIFT_VERSION은 5.0으로 설정되어 있습니다. 이는 빌드 실패를 초래할 수 있습니다. Swift 6.0으로 업그레이드하거나 더 낮은 버전의 lottie-ios를 사용해야 합니다.
라이선스는 Apache License 2.0이며 일반적으로 수용 가능합니다. iOS 배포 대상(17.6, 18.2)은 최소 요구 사항(13.0+)을 충족합니다.
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved`
around lines 13 - 20, The project is using lottie-ios version "4.6.0" (identity
"lottie-ios") which requires Swift 6.0+, while the project SWIFT_VERSION is set
to 5.0; either update the project Swift setting or pin a compatible lottie
version: change the build setting SWIFT_VERSION to "6.0" in your Xcode project
targets (or workspace build settings) and regenerate packages, or update the
"state.version" for identity "lottie-ios" in Package.resolved to a lower
lottie-ios release that supports Swift 5.x and then run SwiftPM update to ensure
the lockfile and dependencies are consistent.
| func makeUIView(context: Context) -> UIView { | ||
| let view = UIView(frame: .zero) | ||
|
|
||
| let animationView = LottieAnimationView(name: animationName) | ||
| animationView.loopMode = loopMode | ||
| animationView.play() | ||
|
|
||
| animationView.translatesAutoresizingMaskIntoConstraints = false | ||
| view.addSubview(animationView) | ||
|
|
||
| NSLayoutConstraint.activate([ | ||
| animationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | ||
| animationView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | ||
| animationView.topAnchor.constraint(equalTo: view.topAnchor), | ||
| animationView.bottomAnchor.constraint(equalTo: view.bottomAnchor) | ||
| ]) | ||
|
|
||
| return view | ||
| } | ||
|
|
||
| func updateUIView(_ uiView: UIView, context: Context) {} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "Lottie+.swift" -type fRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 141
🏁 Script executed:
fd "Lottie\+\.swift" -type fRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 240
🏁 Script executed:
cat -n "./Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Lottie+.swift"Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1331
🌐 Web query:
UIViewRepresentable updateUIView lifecycle SwiftUI best practices
💡 Result:
Key points & best practices for UIViewRepresentable lifecycle (makeUIView / updateUIView)
- Lifecycle basics
- makeUIView(...) is called once to create the UIKit view. updateUIView(_:context:) is called repeatedly whenever SwiftUI considers the representable’s inputs/state changed; after makeUIView it will be called at least once. Use dismantleUIView(...) for cleanup. (developer.apple.com)
- Treat updateUIView as a sync/diff method
- Don’t recreate subviews or do heavy allocation in updateUIView. Apply only the minimal updates needed (set properties, update models, call setNeedsLayout). That keeps SwiftUI diffing fast and avoids flicker. (sarunw.com)
- Use Coordinator for delegates, actions and two‑way bindings
- Put delegate/dataSource handlers and callbacks in Context.coordinator so delegate lifetime and bridging are correct. Use
@Binding/@ObservedObjecton the SwiftUI side and propagate changes in updateUIView or via the coordinator. (ios-swift-explorations.hashnode.dev)
- Be explicit about what triggers updates
- SwiftUI calls updateUIView when inputs change; if you need a full rebuild, change the view’s .id(...) to force re‑creation. Don’t rely on implicit side effects—drive updates from bindings/observable objects. (stackoverflow.com)
- Threading and performance
- All UIKit work must run on the main thread. Offload heavy processing (parsing, layout calculations) to background threads and apply final UI updates in updateUIView on the main thread. Profile with Instruments if performance is a concern. (peerdh.com)
- Cleanup & appearance hooks
- Use dismantleUIView to remove observers/notifications. Complement representable lifecycle with SwiftUI’s onAppear/onDisappear in the parent view when appropriate. (fatbobman.com)
Short checklist when implementing:
- makeUIView: create and configure once.
- updateUIView: apply incremental changes only; read bindings/observables here.
- Coordinator: implement delegates, send events back to SwiftUI.
- Use .id to force recreate only when necessary.
- Keep UIKit updates on main thread; heavy work off the main thread.
- Clean up in dismantleUIView and/or onDisappear.
If you want, I can show a compact example demonstrating these patterns.
Citations:
- 1: https://developer.apple.com/documentation/swiftui/uiviewrepresentable?utm_source=openai
- 2: https://sarunw.com/posts/uiview-in-swiftui/?utm_source=openai
- 3: https://ios-swift-explorations.hashnode.dev/understanding-uiviewrepresentable-and-uiviewcontrollerrepresentable-in-swiftui?utm_source=openai
- 4: https://stackoverflow.com/questions/65461516/how-do-i-trigger-updateuiview-of-a-uiviewrepresentable?utm_source=openai
- 5: https://peerdh.com/blogs/programming-insights/managing-state-changes-in-swiftui-and-uikit-applications?utm_source=openai
- 6: https://fatbobman.com/en/posts/uikitinswiftui/?utm_source=openai
updateUIView가 비어 있어 애니메이션 속성 변경이 반영되지 않음
animationName 또는 loopMode가 변경되어도 updateUIView가 구현되지 않았으므로 UI에 반영되지 않습니다. 특히 동일한 LottieView를 다른 파라미터로 재사용할 때 버그가 발생할 수 있습니다.
Coordinator 패턴을 사용하여 animationView 참조를 유지한 후, updateUIView에서 애니메이션과 루프 모드를 갱신해야 합니다.
🛠️ 제안 수정
struct LottieView: UIViewRepresentable {
let animationName: String
let loopMode: LottieLoopMode
+ func makeCoordinator() -> Coordinator { Coordinator() }
+
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: .zero)
let animationView = LottieAnimationView(name: animationName)
+ context.coordinator.animationView = animationView
animationView.loopMode = loopMode
animationView.play()
animationView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(animationView)
NSLayoutConstraint.activate([
animationView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
animationView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
animationView.topAnchor.constraint(equalTo: view.topAnchor),
animationView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
return view
}
- func updateUIView(_ uiView: UIView, context: Context) {}
+ func updateUIView(_ uiView: UIView, context: Context) {
+ guard let animationView = context.coordinator.animationView else { return }
+ if animationView.animation?.name != animationName {
+ animationView.animation = LottieAnimation.named(animationName)
+ }
+ animationView.loopMode = loopMode
+ animationView.play()
+ }
+
+ final class Coordinator {
+ var animationView: LottieAnimationView?
+ }
}🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Lottie`+.swift around
lines 15 - 35, makeUIView currently creates a new LottieAnimationView but
updateUIView is empty, so changes to animationName or loopMode aren’t applied;
implement the Coordinator pattern to store a persistent reference (e.g.,
coordinator.animationView) when creating the view in makeUIView, assign the
created LottieAnimationView to that coordinator property, and then implement
updateUIView to compare and update the coordinator.animationView: if
animationName changed load/set the new LottieAnimationView animation, update
loopMode, and restart/play as needed so parameter changes are reflected without
recreating the whole SwiftUI view.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/View/ChallengeLoadingView.swift`:
- Around line 21-35: The Lottie animation should respect Reduce Motion and avoid
VoiceOver focus: update ChallengeLoadingView where LottieView(animationName:
"splash", loopMode: .loop) is used to use UIAccessibility.isReduceMotionEnabled
(or `@Environment`(\.accessibilityReduceMotion)) to switch loopMode to a single
play (or replace with a static image) when Reduce Motion is enabled, and add
accessibilityHidden(true) (or .accessibility(hidden: true)) to the LottieView so
it is not focused by VoiceOver; keep the existing layout and text elements
unchanged and only change the LottieView instantiation/attributes.
|
|
||
| LottieView(animationName: "splash", loopMode: .loop) | ||
| .frame(width: 130.adjustedW, height: 154.adjustedH) | ||
| .padding(.top, 60.adjustedH) | ||
|
|
||
| Spacer() | ||
| .frame(height: 80.adjustedH) | ||
|
|
||
| TypographyText("잠시만 기다려주세요!", style: .title2_sb_16, color: .gray800) | ||
| .padding(.top, 17.adjustedH) | ||
|
|
||
| Spacer() | ||
|
|
||
| TypographyText("AI가 맞춤형 루틴을 제작하고 있어요.", style: .body3_m_12, color: .gray600) | ||
| .padding(.bottom, 30.adjustedH) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Reduce Motion 사용자 배려 추가 권장.
반복 루프 애니메이션은 Reduce Motion이 켜진 경우 1회 재생(또는 정적 대체)로 전환하는 편이 접근성에 유리합니다. 애니메이션이 보이스오버 포커스를 받지 않도록 숨김 처리도 권장합니다.
♿ 제안 변경사항
struct ChallengeLoadingView: View {
+ `@Environment`(\.accessibilityReduceMotion) private var reduceMotion
`@ObservedObject` var viewModel: CreateChallengeViewModel
var body: some View {
VStack {
@@
- LottieView(animationName: "splash", loopMode: .loop)
+ LottieView(animationName: "splash", loopMode: reduceMotion ? .playOnce : .loop)
.frame(width: 130.adjustedW, height: 154.adjustedH)
.padding(.top, 60.adjustedH)
+ .accessibilityHidden(true)🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/View/ChallengeLoadingView.swift`
around lines 21 - 35, The Lottie animation should respect Reduce Motion and
avoid VoiceOver focus: update ChallengeLoadingView where
LottieView(animationName: "splash", loopMode: .loop) is used to use
UIAccessibility.isReduceMotionEnabled (or
`@Environment`(\.accessibilityReduceMotion)) to switch loopMode to a single play
(or replace with a static image) when Reduce Motion is enabled, and add
accessibilityHidden(true) (or .accessibility(hidden: true)) to the LottieView so
it is not focused by VoiceOver; keep the existing layout and text elements
unchanged and only change the LottieView instantiation/attributes.
🔗 연결된 이슈
📄 작업 내용