SwiftUI 를 사용해서 개인 프로젝트를 시작하기 위해 기초적인 작업을 맞춰놨다.
일단 기본적으로 MVVM에서 데이터를 전달하는 방식과 RxSwift 를 활용하는 내용을 실전에 활용해 보기 위해 한번 테스트를 해봤다고 생각 하면서 진행했다.
Model 및 ViewModel 생성
struct Workout: Identifiable {
var id = UUID()
var name: String
var date: Date
var duration: TimeInterval
var caloriesBurned: Double
}
운동 기록을 하기 위해 필요한 데이터를 struct로 생성하였다.
import Foundation
import RxSwift
import RxCocoa
class WorkoutViewModel: ObservableObject {
let loadWorkouts = PublishSubject<Void>()
@Published var workouts: [Workout] = []
@Published var errorMessage: String?
private let disposeBag = DisposeBag()
init() {
let dummyWorkouts = [
Workout(name: "Running", date: Date(), duration: 3600, caloriesBurned: 300),
Workout(name: "Swimming", date: Date(), duration: 1800, caloriesBurned: 250),
Workout(name: "Cycling", date: Date(), duration: 5400, caloriesBurned: 500)
]
loadWorkouts
.map { dummyWorkouts }
.subscribe(onNext: { [weak self] workouts in
self?.workouts = workouts
}, onError: { [weak self] error in
self?.errorMessage = error.localizedDescription
})
.disposed(by: disposeBag)
}
}
그 다음 더미 데이터를 만들어 데이터를 전달하고 DisposeBag을 활용해 자동으로 해제될 수 있도록 구현했다.
loadWorkouts의 값을 입력받아 더미데이터가 들어있는 모델링을 불러오는 방식이다.
ObservableObject의 프로토콜을 채택해 SwiftUI와 바인딩 될 수 있도록 설정하고 @Published 프로퍼티 래퍼를 사용하여 workouts와 errorMesseage를 선언한다.
이렇게 설정하면 값이 변경될때 SwiftUI 뷰에 자동으로 업데이트 될 수 있다.
DisposeBag
위에서 언급된 디스포스백을 설명하자면 RxSwift에서 메모리 관리를 도와주는 중요한 도구이다.
RxSwift를 사용하여 생성된 옵저버블 시퀀스들은 무한히 지속될 수 있습니다. 이러한 시퀀스들이 제대로 해제되지 않으면 메모리 누수가 발생할 수 있다.
disposeBag은 이러한 시퀀스들을 한 곳에 모아 두고, DisposeBag이 할당 해제될 때 자동으로 시퀀스들도 함께 해제되도록 하는 명령어이다.
DisposeBag 의 역할
- 메모리 누수 방지 : DisposeBag은 구독을 수집하고 할당 해제될 때 이 구독들도 해제되어 메모리 누수를 방지한다.
- 코드 가독성 향상 : 여러 구독들을 한 곳에 관리하게 되기 때문에 코드가 더 깔끔해지고 가독성이 높아진다.
- 명시적 해제 : 수동으로 구독을 해제하지 않아도 DisposeBag 을 사용하여 구독을 자동으로 해제할 수 있다.
onNext
onNext는 RxSwift에서 사용되는 연산자로 옵저버블에 새로운 이벤트를 방출하는데 사용된다.
View의 구성
import SwiftUI
struct WorkoutsView: View {
@ObservedObject var viewModel = WorkoutViewModel()
var body: some View {
NavigationView {
List(viewModel.workouts) { workout in
HStack {
VStack(alignment: .leading) {
Text(workout.name)
.font(.headline)
Text("\\(formatDuration(workout.duration)) - \\(workout.caloriesBurned) kcal")
}
Spacer()
Image(systemName: "checkmark.seal.fill")
}
}
.navigationTitle("Workouts")
.onAppear {
viewModel.loadWorkouts.onNext(())
}
.alert(item: $viewModel.errorMessage) { message in
Alert(title: Text("Error"), message: Text(message), dismissButton: .default(Text("OK")))
}
}
}
private func formatDuration(_ duration: TimeInterval) -> String {
let hours = Int(duration) / 3600
let minutes = (Int(duration) % 3600) / 60
return String(format: "%02d:%02d", hours, minutes)
}
}
extension String: Identifiable {
public var id: String { self }
}
그 다음 View 내 SwiftUI 를 활용해 컴포넌트들을 호출하고 모델에서 사용된 데이터를 넣어주면 쉽게 데이터 연결이 가능하다.
SwiftUI를 써보면서 느끼는 거지만 확실히 UIKit 보다 컴포넌트 추가가 수월하다..
onAppear
onAppear는 SwiftUI에서 뷰가 화면에 나타날 때 실행되는 코드를 지정하는 뷰 수정자 이다.
SwiftUI의 뷰 라이프 사이클 중에서 뷰가 처음 그려지거나 다시 나타날때 호출되게 된다.
'◽️ Programming > RxSwift' 카테고리의 다른 글
RxSwift에서 Driver란 무엇일까 (0) | 2024.08.26 |
---|---|
[RxSwift] 가장 기본적이고 중요한 Observable에 대해서 알아보자 (0) | 2024.08.20 |
RxSwift 사용해서 TableView, CollectionView 구현하기 (0) | 2024.07.29 |
API 네트워크 통신 과정을 통해 RxSwift 이해하기 (0) | 2024.07.28 |
RxSwift에 대해서 알아보자 (0) | 2024.05.25 |