fix: CommentViewController 음성 녹음 업로드 시 크래시 오류 발생 이슈 수정해요#805
Conversation
…, BBAudioSessionManageable 프로토콜 추가 - 음성 녹음 관련 BBAudioSessionManager, BBRecorderManager Manager 추가 - 음성 녹음 관련 BBMonitoringService, BBPlaybackService, BBRecordingService Service 추가 - ThridParty URL 호출할 수 있도록 Requestable baseUrl Property 추가
Walkthrough오디오 관리 책임을 프로토콜 기반 서비스들로 분리하고, 전역 싱글톤 Changes오디오 관리자 아키텍처 리팩토링
비기능 일관화: Rx 스로틀/스케줄러 교체
Sequence DiagramsequenceDiagram
participant UI as UI (Cell/View/VC)
participant Disk as BBDiskCacheStorage
participant BBM as BBRecorderManager.shared
participant Sess as BBAudioSessionManager
participant Rec as BBRecordingService
participant Play as BBPlaybackService
UI->>BBM: startRecording()
BBM->>Sess: setupSession()\nactivateSession()
BBM->>Rec: startRecording()
Rec-->>BBM: returns recording URL
UI->>BBM: stopRecording()
BBM->>Rec: stopRecording()
BBM-->>UI: audioRecorderDidFinishRecording (observable)
UI->>Disk: read audioURL(audioId)
Disk-->>UI: audioURL or nil
UI->>BBM: play(audioURL)
BBM->>Sess: setupSession()\nactivateSession()
BBM->>Play: play(url)
Play-->>BBM: playback started / throws
BBM-->>UI: emit decibel / currentTime observables
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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.
Pull request overview
This PR addresses crashes and unintended audio capture during voice recording by refactoring the recorder stack (splitting session/record/playback/monitoring responsibilities) and updates the networking layer to support third-party base URLs via Requestable.baseUrl.
Changes:
- Refactors
BBRecorderManagerinto a singleton-backed manager with separate session/recording/playback/monitoring services. - Updates recorder format selection to derive sample rate/channel count from the device input format (and adds helpers for settings dictionary generation).
- Adds
Requestable.baseUrl(defaulting tonil) soSpeccan target non-Bibbi base URLs; updates interceptor token refresh to build requests with a config.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| 14th-team5-iOS/Core/Sources/Extensions/Reactive+Ext.swift | Updates recorder decibel tap format to use the input node’s output format. |
| 14th-team5-iOS/Core/Sources/Extensions/BBRecorderManager+Ext.swift | Removes Rx wrapper for start/stop recording method invocations. |
| 14th-team5-iOS/Core/Sources/Extensions/Array+Ext.swift | Adds [BBRecorderOption] -> [String: Any] conversion helper (asFormat). |
| 14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swift | Makes interceptor configurable and passes config into Spec.urlRequest. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/BBAPISpec.swift | Introduces Requestable.baseUrl and wires it into URL generation; extends Spec accordingly. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift | New recording service using AVAudioRecorder with input-node-derived settings. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBPlaybackService.swift | New playback service wrapping AVAudioPlayer. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift | New monitoring service that taps the input node to emit decibel values. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift | New singleton manager composing session/record/play/monitor services and bridging to existing BBRecorderCore. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift | New session manager abstraction for configuring/activating/deactivating the audio session. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManageable.swift | Adds protocol for audio session management. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift | Adds protocol for recording service. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioPlayable.swift | Adds protocol for playback service. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioMonitorable.swift | Adds protocol for monitoring service. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderOption.swift | Adds input-node-based “safe defaults” and modifies the legacy default options. |
| 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderManager.swift | Deletes the previous monolithic recorder manager implementation. |
| 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/ViewController/CommentViewController.swift | Switches microphone permission request to use the shared recorder manager; removes per-VC manager instance. |
| 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift | Switches recording/time/decibel bindings to the shared recorder manager and makes Data(contentsOf:) non-throwing. |
| 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/Cell/CommentCell.swift | Removes per-cell player manager and routes playback through the shared recorder manager. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private init( | ||
| sessionManager: BBAudioSessionManageable? = nil, | ||
| recordingService: BBAudioRecordable? = nil, | ||
| monitoringService: BBAudioMonitorable? = nil, | ||
| playbackService: BBAudioPlayable? = nil | ||
| ) { | ||
| self.sessionManager = sessionManager ?? BBAudioSessionManager() | ||
| self.recordingService = recordingService ?? BBRecordingService(audioEngine: audioEngine) | ||
| self.monitoringService = monitoringService ?? BBMonitoringService(audioEngine: audioEngine) | ||
| self.playbackService = playbackService ?? BBPlaybackService() | ||
| } |
| //MARK: Property | ||
| private let session: AVAudioSession = AVAudioSession() | ||
|
|
||
| //MARK: Helpers | ||
| public func setupSession() throws { | ||
| try session.setCategory( | ||
| .playAndRecord, | ||
| mode: .voiceChat, | ||
| options: [.defaultToSpeaker, .allowBluetooth] | ||
| ) |
| do { | ||
| try sessionManager.setupSession() | ||
| try sessionManager.activateSession() | ||
|
|
||
| let url = try recordingService.startRecording() | ||
| currentRecordingURL = url | ||
|
|
||
| if !recorderCore.isRecording { | ||
| recorderCore.audioRecorder.record() | ||
| } |
| } | ||
|
|
||
| public var isRecording: Bool { | ||
| return recordingService.isRecoding |
| } | ||
|
|
||
| public func stopPlayback() { | ||
| playbackService.stop() |
| /// 기본 옵션으로 설정하는 메서드 | ||
| static func `default`() -> [BBRecorderOption] { | ||
| return [ | ||
| .formatIDKey(kAudioFormatMPEG4AAC), | ||
| .sampleRate(44100), | ||
| .channelsKey(1), | ||
| .sampleRate(44100.0), | ||
| .channelsKey(2), | ||
| .qualityKey(.high), | ||
| .linearPCMBitDepthKey(16), | ||
| .linearPCMIsBigEndianKey(false), | ||
| .linearPCMIsFloatKey(false) | ||
| ] |
| try? self.audioEngine.start() | ||
|
|
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift (1)
53-57:⚠️ Potential issue | 🟠 Major구독 순서에 따른 녹음 종료 이벤트 손실 위험이 있습니다.
recorderURL을publish().refCount()로 hot하게 공유할 때,do(onNext:)내에서stopRecoding()을 호출한 후에flatMapLatest가 구독하면 이벤트를 놓칠 수 있습니다. hot observable은 구독 시점 이후의 이벤트만 받으므로, 동기적으로 방출되는audioRecorderDidFinishRecording을 놓칠 가능성이 있습니다.구독을 먼저 시작한 후 종료를 트리거하도록 순서를 변경하세요.
수정 예시
confirmButton.rx.tap .throttle(.milliseconds(300), scheduler: RxScheduler.main) - .do(onNext: { BBRecorderManager.shared.stopRecoding() }) - .flatMapLatest { recorderURL } + .flatMapLatest { _ in + recorderURL + .take(1) + .do(onSubscribe: { BBRecorderManager.shared.stopRecording() }) + } .compactMap { try? Data(contentsOf: $0)} .map { Reactor.Action.didTappedRecordConfirmButton($0)} .bind(to: reactor.action)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift` around lines 53 - 57, The hot observable created as recorderURL from BBRecorderManager.shared.recorderCore.audioRecorder.rx.audioRecorderDidFinishRecording.publish().refCount() risks missing the synchronous finish event because stopRecoding() is called inside do(onNext:) after creating recorderURL; change the order so the subscription (the flatMapLatest chain that listens for recorderURL) is established before triggering stopRecoding(). Concretely, in the scope where you use recorderURL, move or reorder the flatMapLatest/subscription setup to occur first (or use an operator that ensures subscription happens before emitting, e.g., concat/take(1)/replay(1) semantics), then call stopRecoding(); reference recorderURL, audioRecorderDidFinishRecording, stopRecoding(), do(onNext:) and flatMapLatest to find the exact spots to reorder.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/Cell/CommentCell.swift`:
- Around line 73-77: The cell deinit hook in CommentCell currently calls
BBRecorderManager.shared.stopPlayback() which will stop the shared player for
the whole screen; instead remove the unconditional stop from the rx.deallocated
binding and either (a) only stop playback when this cell actually owns the
playing audio by checking BBRecorderManager.shared.currentAudioId (or equivalent
API) against the cell's audioId before calling stopPlayback, or (b)
delegate/emit an event to the view controller to handle global playback cleanup
at the screen level; keep the commentEqualizerView.invalidateEqaulizerLayout()
cleanup in the dealloc hook but do not unconditionally call
BBRecorderManager.shared.stopPlayback() from CommentCell.
- Around line 254-259: The play branch currently uses `try?
BBRecorderManager.shared.play(audioURL)` which swallows errors and can leave the
UI in `.play`; change it to a proper do/catch around
`BBRecorderManager.shared.play(audioURL)`, and in the catch set the reactor back
to the `.inital` state (e.g. dispatch the reactor action that sets the playback
state to `.inital`) and surface the error (show an error toast/alert or log) so
the button/equalizer reflect the real state; reference
`BBRecorderManager.shared.play(_:)`, the `.play`/`.inital` state cases in the
switch, and the `reactor` instance to dispatch the rollback action.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift`:
- Line 11: The protocol BBAudioRecordable exposes a typoged property isRecoding
— rename it to isRecording in the protocol declaration and update every
implementation and usage to the new name; to preserve public API compatibility
add a deprecated shim on the protocol (or on conforming types) like a computed
property isRecoding marked `@available`(*, deprecated, renamed: "isRecording")
that returns isRecording, and update related tests and documentation to use
isRecording.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift`:
- Around line 15-18: The MARK comments in BBAudioSessionManager.swift are
formatted as "//MARK:" which triggers SwiftLint; update them to the
SwiftLint-approved form "// MARK: ..." (e.g., change "//MARK: Property" to "//
MARK: Property" and "//MARK: Helpers" to "// MARK: Helpers") in the
BBAudioSessionManager type (where the session property AVAudioSession is
declared) and any other MARK comments in that file to ensure consistent spacing
and casing.
- Line 16: The AVAudioSession instance is being created with AVAudioSession()
which is invalid; update the session property initialization in
BBAudioSessionManager (the private let session) to obtain the singleton via
AVAudioSession.sharedInstance() instead of using a direct initializer so the
session uses the correct shared audio session.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift`:
- Around line 42-68: The issue is that startRecoding()/stopRecoding() starts two
separate AVAudioRecorder instances (recordingService.startRecording() and
recorderCore.audioRecorder.record()) causing UI streams
(rx.audioRecorderDidFinishRecording and requestCurrentTime reading
recorderCore.audioRecorder.currentTime) to monitor the wrong file; fix by using
a single recorder: remove the concurrent
recorderCore.audioRecorder.record()/stop() calls and instead wire the UI streams
to the recorder instance returned/owned by recordingService (update observers
that reference rx.audioRecorderDidFinishRecording and requestCurrentTime to read
from recordingService's AVAudioRecorder/currentTime), ensure currentRecordingURL
is set from recordingService.startRecording() and that stopRecoding() stops only
recordingService and deactivates session so only one AVAudioRecorder is active
and UI events reflect the actual upload file.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift`:
- Around line 28-42: The Observable currently installs an AVAudioNode tap on
each subscription (audioEngine.inputNode.installTap inside Observable.create)
which can crash if a tap already exists and also hides start errors via try?;
fix by ensuring the tap is installed only once (move installTap out of
Observable.create or gate it with a shared boolean/lock tied to the
BBMonitoringService instance) and only remove the tap when the shared owner
truly disposes (coordinate dispose so removeTap(onBus:) in Disposables.create
only runs when the shared tap owner is torn down), and replace try?
self.audioEngine.start() with proper error handling that forwards failures
(e.g., propagate NSError via observer.onError) so engine start failures are not
silently ignored.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift`:
- Around line 39-43: The method that creates audioRecoder (in BBRecordingService
where audioRecoder = try AVAudioRecorder(...)) currently returns the file URL
even if recording didn't actually start; change it to call and check
prepareToRecord() and the Bool result of record(), and only return the URL when
both succeed. If prepareToRecord() or record() return false, stop/cleanup the
audioRecoder instance (set audioRecoder = nil and call stop() if needed) and
return a failure indicator (nil or throw an error) instead of the URL so callers
don't assume recording started.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swift`:
- Around line 98-100: In BBNetworkInterceptor.swift, when
endpoint.urlRequest(config) fails the current guard just returns without
invoking the completion handler; change this so the failure is propagated by
calling the existing completion handler with an appropriate error (e.g., a
URLRequestCreationError or propagated endpoint error) instead of returning
silently. Locate the guard around endpoint.urlRequest(config) in the method that
receives the completion closure and replace the early return with a call to
completion(.failure(...)) (or the project’s Result/Error pattern) so callers’
retry logic can observe the failure.
---
Outside diff comments:
In
`@14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift`:
- Around line 53-57: The hot observable created as recorderURL from
BBRecorderManager.shared.recorderCore.audioRecorder.rx.audioRecorderDidFinishRecording.publish().refCount()
risks missing the synchronous finish event because stopRecoding() is called
inside do(onNext:) after creating recorderURL; change the order so the
subscription (the flatMapLatest chain that listens for recorderURL) is
established before triggering stopRecoding(). Concretely, in the scope where you
use recorderURL, move or reorder the flatMapLatest/subscription setup to occur
first (or use an operator that ensures subscription happens before emitting,
e.g., concat/take(1)/replay(1) semantics), then call stopRecoding(); reference
recorderURL, audioRecorderDidFinishRecording, stopRecoding(), do(onNext:) and
flatMapLatest to find the exact spots to reorder.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 943e6f41-8528-4df8-84fc-1914cd6ec630
📒 Files selected for processing (19)
14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/Cell/CommentCell.swift14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift14th-team5-iOS/Bibbi/Sources/Presentation/Comment/ViewController/CommentViewController.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderOption.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioMonitorable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioPlayable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManageable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBPlaybackService.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/BBAPISpec.swift14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swift14th-team5-iOS/Core/Sources/Extensions/Array+Ext.swift14th-team5-iOS/Core/Sources/Extensions/BBRecorderManager+Ext.swift14th-team5-iOS/Core/Sources/Extensions/Reactive+Ext.swift
💤 Files with no reviewable changes (2)
- 14th-team5-iOS/Core/Sources/Extensions/BBRecorderManager+Ext.swift
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderManager.swift
| //MARK: Property | ||
| private let session: AVAudioSession = AVAudioSession() | ||
|
|
||
| //MARK: Helpers |
There was a problem hiding this comment.
MARK 주석 포맷을 SwiftLint 규칙에 맞춰주세요.
현재 //MARK: 형식이라 린트 경고가 발생합니다.
제안 수정안
- //MARK: Property
+ // MARK: - Property
@@
- //MARK: Helpers
+ // MARK: - Helpers📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| //MARK: Property | |
| private let session: AVAudioSession = AVAudioSession() | |
| //MARK: Helpers | |
| // MARK: - Property | |
| private let session: AVAudioSession = AVAudioSession() | |
| // MARK: - Helpers |
🧰 Tools
🪛 SwiftLint (0.63.2)
[Warning] 15-15: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'
(mark)
[Warning] 18-18: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'
(mark)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift`
around lines 15 - 18, The MARK comments in BBAudioSessionManager.swift are
formatted as "//MARK:" which triggers SwiftLint; update them to the
SwiftLint-approved form "// MARK: ..." (e.g., change "//MARK: Property" to "//
MARK: Property" and "//MARK: Helpers" to "// MARK: Helpers") in the
BBAudioSessionManager type (where the session property AVAudioSession is
declared) and any other MARK comments in that file to ensure consistent spacing
and casing.
| guard let urlRequest = try? endpoint.urlRequest(config) else { | ||
| return | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify BBNetworkSession.request(with:completion:) and refreshAuthToken error propagation.
rg -nP --type=swift -C 6 '\bfunc\s+request\s*\(with:\s*URLRequest' 14th-team5-iOS/Core/Sources
rg -nP --type=swift -C 6 '\brefreshAuthToken\s*\(' 14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swiftRepository: depromeet/14th-team5-iOS
Length of output: 1016
🏁 Script executed:
cat -n 14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swift | sed -n '85,110p'Repository: depromeet/14th-team5-iOS
Length of output: 784
URLRequest 생성 실패를 상위로 전달하세요.
endpoint.urlRequest(config)가 실패하면 return 문으로 나가면서 completion 핸들러를 호출하지 않습니다. 이로 인해 호출자의 재시도 로직이 영원히 대기 상태에 머물게 됩니다. 실패 시에도 completion 핸들러를 호출하여 오류를 전파해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkInterceptor.swift`
around lines 98 - 100, In BBNetworkInterceptor.swift, when
endpoint.urlRequest(config) fails the current guard just returns without
invoking the completion handler; change this so the failure is propagated by
calling the existing completion handler with an appropriate error (e.g., a
URLRequestCreationError or propagated endpoint error) instead of returning
silently. Locate the guard around endpoint.urlRequest(config) in the method that
receives the completion closure and replace the early return with a call to
completion(.failure(...)) (or the project’s Result/Error pattern) so callers’
retry logic can observe the failure.
- BBRecordingService 오타 수정 및 에러 처리 추가 - BBRecorderOption 사용하지 않은 전역 변수 제거 - Tuist CFBundleShortVersionString 1.5.1로 변경
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift (1)
15-18:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
MARK주석 포맷을 SwiftLint 형식으로 통일해주세요.Line 15, Line 18의
//MARK:는 린트 경고 대상입니다.// MARK: - ...형식으로 바꾸는 게 좋습니다.제안 수정안
- //MARK: Property + // MARK: - Property @@ - //MARK: Helpers + // MARK: - Helpers🤖 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 `@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift` around lines 15 - 18, Update the MARK comments in BBAudioSessionManager to SwiftLint-compliant format: replace the two occurrences of "//MARK: Property" and "//MARK: Helpers" with the spaced and dashed form "// MARK: - Property" and "// MARK: - Helpers" so the class (BBAudioSessionManager) and the private let session: AVAudioSession = AVAudioSession.sharedInstance() property don't trigger lint warnings.
🤖 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
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift`:
- Around line 114-122: In stopRecording(), ensure
sessionManager.deactivateSession() runs even if recordingService.stopRecording()
throws by moving the deactivation into a defer block; call try
recordingService.stopRecording() and set currentRecordingURL = nil inside the
do/try scope, then add defer { try? sessionManager.deactivateSession() } (or
handle the deactivation error appropriately) so the audio session is always
deactivated regardless of errors from recordingService.stopRecording().
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift`:
- Around line 16-17: isMonitoring 상태가 여러 스레드에서 동시 접근되어 경쟁 상태가 발생할 수 있습니다;
BBMonitoringService의 isMonitoring 읽기/쓰기를 직렬화하여 스레드 안전하게 만드세요. 구체적으로는
BBMonitoringService에 private serial DispatchQueue(예: stateQueue)를 추가하고
isMonitoring에 접근하는 모든 곳(변수 선언부와 startMonitoring, stopMonitoring, dispose 등 해당
메서드들)에서 stateQueue.sync/async로 읽기·쓰기하도록 래핑하여 상태 변경과 검사를 원자적으로 수행하도록 수정하세요.
---
Duplicate comments:
In
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift`:
- Around line 15-18: Update the MARK comments in BBAudioSessionManager to
SwiftLint-compliant format: replace the two occurrences of "//MARK: Property"
and "//MARK: Helpers" with the spaced and dashed form "// MARK: - Property" and
"// MARK: - Helpers" so the class (BBAudioSessionManager) and the private let
session: AVAudioSession = AVAudioSession.sharedInstance() property don't trigger
lint warnings.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 36ca38d5-0c00-4bf1-a1a4-028c192a6880
📒 Files selected for processing (11)
14th-team5-iOS/Bibbi/Project.swift14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/Cell/CommentCell.swift14th-team5-iOS/Bibbi/Sources/Presentation/Comment/ViewController/CommentViewController.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderOption.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioMonitorable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioSessionManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swiftTuist/ProjectDescriptionHelpers/Project+Templates.swift
✅ Files skipped from review due to trivial changes (2)
- Tuist/ProjectDescriptionHelpers/Project+Templates.swift
- 14th-team5-iOS/Bibbi/Project.swift
🚧 Files skipped from review as they are similar to previous changes (5)
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioMonitorable.swift
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift
- 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/ViewController/CommentViewController.swift
- 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/Cell/CommentCell.swift
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift
| @objc public func stopRecording() { | ||
| do { | ||
| try recordingService.stopRecording() | ||
| currentRecordingURL = nil | ||
|
|
||
| try sessionManager.deactivateSession() | ||
| } catch { | ||
| print("녹음 중지 실패: \(error)") | ||
| } |
There was a problem hiding this comment.
stopRecording() 실패 경로에서도 세션 비활성화가 필요합니다.
Line 116에서 에러가 나면 Line 119가 실행되지 않아 오디오 세션이 활성 상태로 남을 수 있습니다. defer로 비활성화를 보장하는 편이 안전합니다.
제안 수정안
`@objc` public func stopRecording() {
- do {
- try recordingService.stopRecording()
- currentRecordingURL = nil
-
- try sessionManager.deactivateSession()
- } catch {
- print("녹음 중지 실패: \(error)")
- }
+ defer { try? sessionManager.deactivateSession() }
+ do {
+ try recordingService.stopRecording()
+ currentRecordingURL = nil
+ } catch {
+ print("녹음 중지 실패: \(error)")
+ }
}🤖 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
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift`
around lines 114 - 122, In stopRecording(), ensure
sessionManager.deactivateSession() runs even if recordingService.stopRecording()
throws by moving the deactivation into a defer block; call try
recordingService.stopRecording() and set currentRecordingURL = nil inside the
do/try scope, then add defer { try? sessionManager.deactivateSession() } (or
handle the deactivation error appropriately) so the audio session is always
deactivated regardless of errors from recordingService.stopRecording().
| private var isMonitoring = false | ||
|
|
There was a problem hiding this comment.
isMonitoring 접근이 스레드 안전하지 않습니다.
Line 27/36/61/67/71에서 isMonitoring을 동기화 없이 읽고/쓰고 있어 경쟁 상태가 발생할 수 있습니다. start/stop/dispose가 다른 스레드에서 호출되면 상태가 꼬일 수 있습니다.
제안 수정안
public final class BBMonitoringService: BBAudioMonitorable {
private let audioEngine: AVAudioEngine
+ private let monitorLock = NSLock()
private var isMonitoring = false
@@
- if self.isMonitoring {
+ self.monitorLock.lock()
+ defer { self.monitorLock.unlock() }
+ if self.isMonitoring {
observer.onError(NSError(
@@
- self.isMonitoring = true
+ self.isMonitoring = true
@@
return Disposables.create { [weak self] in
- self?.audioEngine.inputNode.removeTap(onBus: 0)
- self?.audioEngine.stop()
- self?.isMonitoring = false
+ guard let self else { return }
+ self.monitorLock.lock()
+ defer { self.monitorLock.unlock() }
+ self.audioEngine.inputNode.removeTap(onBus: 0)
+ self.audioEngine.stop()
+ self.isMonitoring = false
}
}
}
@@
public func stopAudioMonitoring() {
+ monitorLock.lock()
+ defer { monitorLock.unlock() }
guard isMonitoring else { return }Also applies to: 27-37, 58-62, 66-71
🤖 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
`@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBMonitoringService.swift`
around lines 16 - 17, isMonitoring 상태가 여러 스레드에서 동시 접근되어 경쟁 상태가 발생할 수 있습니다;
BBMonitoringService의 isMonitoring 읽기/쓰기를 직렬화하여 스레드 안전하게 만드세요. 구체적으로는
BBMonitoringService에 private serial DispatchQueue(예: stateQueue)를 추가하고
isMonitoring에 접근하는 모든 곳(변수 선언부와 startMonitoring, stopMonitoring, dispose 등 해당
메서드들)에서 stateQueue.sync/async로 읽기·쓰기하도록 래핑하여 상태 변경과 검사를 원자적으로 수행하도록 수정하세요.
- Legacy 코드 제거
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
14th-team5-iOS/Bibbi/Sources/Presentation/OnBoarding/OnBoardingViewController.swift (1)
113-113:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win스케줄러 상수 사용이 일관되지 않아요.
이 파일의 Line 128에서는
RxScheduler.main을 사용하는데, Line 113에서는 아직 이전 상수인RxSchedulers.main을 사용하고 있어요. 일관성을 위해 Line 113도RxScheduler.main으로 업데이트하는 것이 좋겠어요.♻️ 일관성 개선을 위한 제안
currentPage .distinctUntilChanged() .withUnretained(self) - .observe(on: RxSchedulers.main) + .observe(on: RxScheduler.main) .bind(onNext: {🤖 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 `@14th-team5-iOS/Bibbi/Sources/Presentation/OnBoarding/OnBoardingViewController.swift` at line 113, In OnBoardingViewController update the Rx scheduler constant usage for consistency: locate the call that currently reads observe(on: RxSchedulers.main) and change it to use the new constant observe(on: RxScheduler.main); ensure any other occurrences in the class use RxScheduler (not RxSchedulers) so the OnBoardingViewController uses the same scheduler symbol throughout.14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/BibbiNavigationBarView.swift (1)
1-371:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftTrash 폴더의 코드가 활성 코드베이스에서 사용되고 있습니다.
이 파일이
Trash폴더에 위치하면서 동시에 다음 활성 코드에서 직접 사용되고 있습니다:
Core/Sources/Base/BaseViewController.swift(핵심 기본 클래스)Core/Sources/Base/BasePageViewController.swift(핵심 기본 클래스)Bibbi/Sources/Presentation/Camera/ImageGenerateViewController.swift더 최신의
BBNavigationBar구현체가 이미 존재하는 상황에서 구형 코드를 계속 유지보수하는 것은 기술 부채를 증가시킵니다. 다음 중 하나의 조치가 필요합니다:
BibbiNavigationBarView를 Trash 폴더에서 꺼내어 적절한 위치로 이동- 전체 코드베이스를
BBNavigationBar로 마이그레이션하고BibbiNavigationBarView삭제🤖 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 `@14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/BibbiNavigationBarView.swift` around lines 1 - 371, The BibbiNavigationBarView implementation in Trash is still referenced by active code (BaseViewController, BasePageViewController, ImageGenerateViewController); remove this tech debt by either (A) relocating BibbiNavigationBarView into the active Core module (remove from Trash) and keeping all public symbols (BibbiNavigationBarView, LeftBarItem, CenterBarItem, RightBarItem, setNavigationView, Reactive extensions leftButtonTap/rightButtonTap) intact, or (B) migrating callers to the newer BBNavigationBar and deleting BibbiNavigationBarView: update all usages in BaseViewController, BasePageViewController, and ImageGenerateViewController to use BBNavigationBar APIs (map left/right/center configuration and reactive taps to BBNavigationBar equivalents) then remove the Trash file and its enums/reactive extensions. Ensure API compatibility or adapt call sites to match BBNavigationBar method/property names and preserve behavior (leftBarItem state, images, backgrounds, and tap throttling).
🤖 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 `@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderCore.swift`:
- Line 29: The current code force-unwraps AVAudioRecorder initialization (return
try! AVAudioRecorder(...)) which can crash; replace the force-try with proper
error handling by making the method a throwing function or a failable
initializer (e.g., change the method that returns the recorder into
createAudioRecorder() throws -> AVAudioRecorder or -> AVAudioRecorder?), call
try when constructing AVAudioRecorder with Self.getDocumentsPath and
BBRecorderOption.default(inputNode: inputNode).asFormat(), and propagate or
handle errors: on throw propagate the error to the caller (or return nil for a
failable path) and add logging of the error and a safe fallback so the app
doesn’t crash when the file URL is invalid or settings are incompatible.
In `@14th-team5-iOS/Core/Sources/Trash/BBNetwork/API.swift`:
- Line 56: The X-APP-KEY is hardcoded in the API file (the enum case returning
the literal for .xAppKey); change it to read the value from a runtime
configuration source (e.g., Bundle.main.object(forInfoDictionaryKey:) or an
injected configuration/Environment struct populated from Info.plist/xcconfig)
instead of the literal, and add a clear fallback/error path (log and fail fast
or return nil) if the key is missing; update the code paths that reference the
.xAppKey case (the API/Headers enum or method that builds headers) to handle the
optional/missing value accordingly so the key can be rotated via plist/xcconfig
without code changes.
In `@14th-team5-iOS/Data/Sources/Repositories/AppRepository.swift`:
- Line 35: The app key is hardcoded in AppRepository as the variable appKey
which risks divergence from the canonical value; replace this literal with a
single source of truth (e.g., reference the constant defined in API or a new
shared Configuration/Constants struct), update AppRepository to read that shared
constant instead of "606cf327-d2f9-4dd7-982e-bdc1412af2b8", and ensure other
places (like API.swift) also reference the same constant (e.g.,
Configuration.appKey or API.clientKey) so key rotation only requires one change.
---
Outside diff comments:
In
`@14th-team5-iOS/Bibbi/Sources/Presentation/OnBoarding/OnBoardingViewController.swift`:
- Line 113: In OnBoardingViewController update the Rx scheduler constant usage
for consistency: locate the call that currently reads observe(on:
RxSchedulers.main) and change it to use the new constant observe(on:
RxScheduler.main); ensure any other occurrences in the class use RxScheduler
(not RxSchedulers) so the OnBoardingViewController uses the same scheduler
symbol throughout.
In
`@14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/BibbiNavigationBarView.swift`:
- Around line 1-371: The BibbiNavigationBarView implementation in Trash is still
referenced by active code (BaseViewController, BasePageViewController,
ImageGenerateViewController); remove this tech debt by either (A) relocating
BibbiNavigationBarView into the active Core module (remove from Trash) and
keeping all public symbols (BibbiNavigationBarView, LeftBarItem, CenterBarItem,
RightBarItem, setNavigationView, Reactive extensions
leftButtonTap/rightButtonTap) intact, or (B) migrating callers to the newer
BBNavigationBar and deleting BibbiNavigationBarView: update all usages in
BaseViewController, BasePageViewController, and ImageGenerateViewController to
use BBNavigationBar APIs (map left/right/center configuration and reactive taps
to BBNavigationBar equivalents) then remove the Trash file and its
enums/reactive extensions. Ensure API compatibility or adapt call sites to match
BBNavigationBar method/property names and preserve behavior (leftBarItem state,
images, backgrounds, and tap throttling).
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 75906492-37a9-451a-9284-2d3f2c25ef90
📒 Files selected for processing (27)
14th-team5-iOS/Bibbi/Sources/Presentation/Account/AccountSignUp/ViewControllers/AccountDateViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Account/AccountSignUp/ViewControllers/AccountNicknameViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Account/AccountSignUp/ViewControllers/AccountProfileViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift14th-team5-iOS/Bibbi/Sources/Presentation/FamilyEntrance/ViewController/FamilyEntranceViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/FamilyEntrance/ViewController/InputFamilyLinkViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/FamilyEntrance/ViewController/JoinFamilyViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Home/ViewControllers/MainFamilyViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Home/ViewControllers/MainViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Home/ViewControllers/pages/MainPostViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/Management/ViewController/FamilyNameSettingViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/OnBoarding/OnBoardingViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/ReactionMembersViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/ReactionViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/SelectableEmojiViewController.swift14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/Views/PostDetailCollectionViewCell.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderCore.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift14th-team5-iOS/Core/Sources/Extensions/Reactive+Ext.swift14th-team5-iOS/Core/Sources/Trash/BBNetwork/API.swift14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/BibbiNavigationBarView.swift14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/DelegateProxy/RxBibbiNavigationDelegateProxy.swift14th-team5-iOS/Core/Sources/Trash/Lottie/BibbiLottileIndicator.swift14th-team5-iOS/Data/Sources/Repositories/AppRepository.swift
💤 Files with no reviewable changes (3)
- 14th-team5-iOS/Core/Sources/Trash/BibbiNavigationBarView/DelegateProxy/RxBibbiNavigationDelegateProxy.swift
- 14th-team5-iOS/Core/Sources/Trash/Lottie/BibbiLottileIndicator.swift
- 14th-team5-iOS/Bibbi/Sources/Presentation/Management/ViewController/FamilyNameSettingViewController.swift
✅ Files skipped from review due to trivial changes (2)
- 14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift
- 14th-team5-iOS/Bibbi/Sources/Presentation/PostDetail/ViewControllers/ReactionViewController.swift
🚧 Files skipped from review as they are similar to previous changes (5)
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBAudioRecordable.swift
- 14th-team5-iOS/Core/Sources/Extensions/Reactive+Ext.swift
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderService/BBRecordingService.swift
- 14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/RecoderManager/BBRecorderManager.swift
- 14th-team5-iOS/Bibbi/Sources/Presentation/Comment/View/CommentTextFieldView.swift
| /// `AVAudioRecorder` 생성자 Property 입니다. | ||
| public lazy var audioRecorder: AVAudioRecorder = { | ||
| return try! AVAudioRecorder(url: Self.getDocumentsPath, settings: BBRecorderOption.default().asFormat()) | ||
| return try! AVAudioRecorder(url: Self.getDocumentsPath, settings: BBRecorderOption.default(inputNode: inputNode).asFormat()) |
There was a problem hiding this comment.
try! 강제 언래핑을 제거하고 적절한 에러 핸들링을 추가해주세요.
AVAudioRecorder 초기화 시 try!를 사용하면 초기화 실패 시 앱이 크래시됩니다. PR의 목적이 크래시 방지인 만큼, 여기서도 안전한 에러 처리가 필요합니다.
예를 들어:
- 파일 URL이 유효하지 않을 경우
- 오디오 설정이 디바이스와 호환되지 않을 경우
이러한 상황에서도 안전하게 처리할 수 있도록 개선이 필요합니다.
🛡️ 안전한 초기화를 위한 제안
Option 1: failable initializer로 변경
-public lazy var audioRecorder: AVAudioRecorder = {
- return try! AVAudioRecorder(url: Self.getDocumentsPath, settings: BBRecorderOption.default(inputNode: inputNode).asFormat())
-}()
+public lazy var audioRecorder: AVAudioRecorder? = {
+ return try? AVAudioRecorder(url: Self.getDocumentsPath, settings: BBRecorderOption.default(inputNode: inputNode).asFormat())
+}()Option 2: throwing 메서드로 변경
public func createAudioRecorder() throws -> AVAudioRecorder {
return try AVAudioRecorder(
url: Self.getDocumentsPath,
settings: BBRecorderOption.default(inputNode: inputNode).asFormat()
)
}🤖 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 `@14th-team5-iOS/Core/Sources/Bibbi/BBCommons/BBRecorder/BBRecorderCore.swift`
at line 29, The current code force-unwraps AVAudioRecorder initialization
(return try! AVAudioRecorder(...)) which can crash; replace the force-try with
proper error handling by making the method a throwing function or a failable
initializer (e.g., change the method that returns the recorder into
createAudioRecorder() throws -> AVAudioRecorder or -> AVAudioRecorder?), call
try when constructing AVAudioRecorder with Self.getDocumentsPath and
BBRecorderOption.default(inputNode: inputNode).asFormat(), and propagate or
handle errors: on throw propagate the error to the caller (or return nil for a
failable path) and add logging of the error and a safe fallback so the app
doesn’t crash when the file URL is invalid or settings are incompatible.
| switch self { | ||
| case let .auth(token): return "Bearer \(token)" | ||
| case .xAppKey: return "cec77ebf-b7fa-4d10-8746-eca496acbf6c" // TODO: - 번들에서 가져오기 | ||
| case .xAppKey: return "606cf327-d2f9-4dd7-982e-bdc1412af2b8" // TODO: - 번들에서 가져오기 |
There was a problem hiding this comment.
X-APP-KEY 하드코딩은 제거가 필요합니다.
Line 56의 리터럴 키는 유출/로테이션 리스크가 큽니다. 최소한 런타임 설정(Info.plist/xcconfig 주입)에서 읽도록 바꿔 주세요.
🔧 제안 수정안
- case .xAppKey: return "606cf327-d2f9-4dd7-982e-bdc1412af2b8" // TODO: - 번들에서 가져오기
+ case .xAppKey:
+ guard
+ let appKey = Bundle.main.object(forInfoDictionaryKey: "X_APP_KEY") as? String,
+ !appKey.isEmpty
+ else {
+ assertionFailure("Missing X_APP_KEY in Info.plist")
+ return ""
+ }
+ return appKey📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case .xAppKey: return "606cf327-d2f9-4dd7-982e-bdc1412af2b8" // TODO: - 번들에서 가져오기 | |
| case .xAppKey: | |
| guard | |
| let appKey = Bundle.main.object(forInfoDictionaryKey: "X_APP_KEY") as? String, | |
| !appKey.isEmpty | |
| else { | |
| assertionFailure("Missing X_APP_KEY in Info.plist") | |
| return "" | |
| } | |
| return appKey |
🤖 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 `@14th-team5-iOS/Core/Sources/Trash/BBNetwork/API.swift` at line 56, The
X-APP-KEY is hardcoded in the API file (the enum case returning the literal for
.xAppKey); change it to read the value from a runtime configuration source
(e.g., Bundle.main.object(forInfoDictionaryKey:) or an injected
configuration/Environment struct populated from Info.plist/xcconfig) instead of
the literal, and add a clear fallback/error path (log and fail fast or return
nil) if the key is missing; update the code paths that reference the .xAppKey
case (the API/Headers enum or method that builds headers) to handle the
optional/missing value accordingly so the key can be rotated via plist/xcconfig
without code changes.
| public func fetchAppVersion() -> Observable<AppVersionEntity> { | ||
| // TODO: - xAppKey 불러오는 코드 다시 작성하기 | ||
| let appKey = "cec77ebf-b7fa-4d10-8746-eca496acbf6c" | ||
| let appKey = "606cf327-d2f9-4dd7-982e-bdc1412af2b8" |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
앱 키를 여기서 재하드코딩하지 말고 단일 소스 값을 재사용하세요.
Line 35는 키 로테이션 시 API.swift와 값 불일치가 나기 쉬운 지점입니다. 한 곳에서만 관리되는 값을 참조하도록 바꾸는 게 안전합니다.
♻️ 제안 수정안
+import Core
import Domain
import Foundation
@@
- let appKey = "606cf327-d2f9-4dd7-982e-bdc1412af2b8"
+ let appKey = BibbiHeader.xAppKey.value🧰 Tools
🪛 Betterleaks (1.2.0)
[high] 35-35: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🤖 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 `@14th-team5-iOS/Data/Sources/Repositories/AppRepository.swift` at line 35, The
app key is hardcoded in AppRepository as the variable appKey which risks
divergence from the canonical value; replace this literal with a single source
of truth (e.g., reference the constant defined in API or a new shared
Configuration/Constants struct), update AppRepository to read that shared
constant instead of "606cf327-d2f9-4dd7-982e-bdc1412af2b8", and ensure other
places (like API.swift) also reference the same constant (e.g.,
Configuration.appKey or API.clientKey) so key rotation only requires one change.
🔵PR을 올리기 전 아래 사항을 확인해주세요.
😽개요
🛠️작업 내용
BBRecorder 폴더 내부 Service, Manager 책임 분리
BBAudioSessionManager을 통해서 AVAudioSession 설정을 관리하도록 구현했습니다.BBRecordingService내부에 오디오 녹음 기능을 전담하도록 구현BBMonitoringService실시간 오디오 데시벨을 측정하도록 기능 구현BBAudioPlayable녹음된 파일(URL)을 재생하도록 기능 구현강제 크래시 오류 현상 해결
AVAudioInputNode에 따라 channel과 sampleRate 값을 지정하도록 수정🛠️작업 내용
Third Party URL 호환 되도록
Requestable내부baseURLProperty 추가Kakao Maps API,itunes API,Google등 외부 Base URL 사용 시Spec을 사용해서 호출 할 수 있도록 내부 구조 변경Base URL이 nil 일 경우Bibbi API URL을 호출 하도록 추가🟡차후 계획 (Optional)
BBAPI를 사용해서 리펙토링 하시면 될 것 같습니다.✅테스트 케이스
IsFormatSampleRateAndChannelCountValid🙏🏻아래와 같이 PR을 리뷰해주세요.
close
Summary by CodeRabbit
릴리스 노트