오늘은 (SwiftUI 버전) 나만의 Todo 앱의 Recording(녹음) 기능을 리뷰하려고 합니다.
이번 기능은 전체적인 흐름이 UIKit에서 구현하던 것과 거의 비슷한 구조라서,
이번 글에서는 녹음을 담당하는 코드에 대해서 자세히 알아 볼려고 합니다.
UIKit 구현이 궁금하신 분들은 아래 글을 참고하시면 될 것 같아요!
👉 [UIKit] 녹음 기능 리뷰 (Feat. 나만의 Todo)
Riu 개발노트
안녕하세요 iOS 개발자를 꿈꾸는 Riu입니다. Github: woolnd
riu-dev.tistory.com
RecordingManager
역할
- 녹음/재생/초기화 전반을 담당하는 Manager 클래스
- SwiftUI에서 사용할 수 있도록 ObservableObject 채택
- AVFoundation 사용 (AVAudioRecorder + AVAudioPlayer 활용)
주요 속성 설명
@Published var isRecording = false
@Published var isPlaying = false
@Published var recordingTime: String = "00:00"
- UI 상태 업데이트를 위해 @Published 사용하였습니다.
- 녹음 중 / 재생 중 여부를 SwiftUI 화면과 바인딩 가능하게 하였습니다.
- 녹음 시간은 “MM:SS” 형식으로 실시간 표시하였습니다.
private var audioRecorder: AVAudioRecorder?
private var audioPlayer: AVAudioPlayer?
private var timer: Timer?
private var startTime: Date?
- AVFoundation의 Recorder/Player 인스턴스
- Timer → 녹음 시간 업데이트에 이용합니다.
- startTime → 녹음 시작 시각 저장합니다.
private(set) var recordedFileURL: URL?
private(set) var currentFileName: String?
- 녹음된 파일 URL, 파일명 저장 → 외부에서는 읽기만 가능하게 하였습니다. (private(set))
주요 메서드 리뷰
1️⃣ toggleRecordingOrPlayback()
if isRecording {
stopRecording()
} else if let url = recordedFileURL, FileManager.default.fileExists(atPath: url.path) {
playRecording()
} else {
let autoGeneratedFileName = UUID().uuidString
currentFileName = autoGeneratedFileName
startRecording(fileName: autoGeneratedFileName)
}
- 하나의 메서드에서 녹음/재생/녹음 시작 로직을 모두 처리하였습니다.
- isRecording 중이면 중지
- 녹음 파일 있으면 재생
- 파일 없으면 새로 녹음 시작
audioRecorder?.stop()
isRecording = false
stopTimer()
👍 장점 → 버튼 1개로 다양한 상태 전환 가능하게 하였습니다.
2️⃣ startRecording(fileName:)
let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("\(fileName).m4a")
- Documents 디렉토리에 m4a 파일 저장합니다.
try session.setCategory(.playAndRecord, mode: .default)
try session.setActive(true)
- AVAudioSession 설정 → 녹음/재생 모두 가능하게 설정합니다.
audioRecorder?.record()
isRecording = true
isPlaying = false
startTime = Date()
startTimer()
- 녹음 시작 + UI 업데이트 + Timer 시작 → 녹음 시간 표시 가능
3️⃣ stopRecording()
audioRecorder?.stop()
isRecording = false
stopTimer()
- 녹음 중지 → Timer도 함께 중지합니다.
4️⃣ playRecording()
try session.overrideOutputAudioPort(.speaker)
- 스피커로 강제로 출력 → 이어폰 사용 시에도 강제 스피커 출력 가능합니다.
audioPlayer?.play()
isPlaying = true
- 녹음 파일 재생 시작 + UI 업데이트
👍 장점 → 녹음과 재생 시 AVAudioSession 을 따로 설정해주었습니다.
5️⃣ audioPlayerDidFinishPlaying()
isPlaying = false
- 재생 완료 시 UI 상태 업데이트하도록 AVAudioPlayerDelegate을 활용하였습니다.
6️⃣ startTimer() & stopTimer()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true)
- 1초마다 호출 → 녹음 시간 업데이트
- "MM:SS" 형식
👍 장점 → Timer 사용법 깔끔함, 메모리 관리도 invalidate()로 잘 마무리하였습니다.
7️⃣ resetRecording()
stopRecording()
isRecording = false
if let url = recordedFileURL, FileManager.default.fileExists(atPath: url.path) {
try? FileManager.default.removeItem(at: url)
}
- 녹음 파일 삭제 → Documents 디렉토리에서 파일을 정리하였습니다.
- 상태 초기화 → UI에 반영 가능하게 하였습니다.
👍 장점 → 초기화 시 파일 정리까지 해줘서 불필요한 파일 누적 방지하였습니다.
🧩 마무리
이번 포스팅에서는 나만의 Todo 앱에서 녹음하는 기능에 초첨을 맞춰서 소개해보았습니다.
📌 녹음 기능의 전체 코드가 궁금하신 분들은 아래 GitHub 링크를 참고해주세요:
GitHub - woolnd/SwiftUI_MyTodo
Contribute to woolnd/SwiftUI_MyTodo development by creating an account on GitHub.
github.com
다음 포스팅에서는 앱 내 또 다른 기능인 ⏱ 타이머 기능을소개드릴 예정이니 기대해주세요!
꾸준히 기록하며 성장하는 개발자가 되기 위해 계속 달려보겠습니다! 🚀
읽어주셔서 감사합니다 😊