RxSwift에 대해서 알아보자
RxSwift는 iOS와 macOS 개발에서 사용되는 반응형 프로그래밍 라이브러리이다. 이 라이브러리는 Rx(Reactive Extensions) 패턴을 기반으로 하며, 비동기 데이터 스트림을 쉽게 처리하고 관리할 수 있게 해준다.
RxSwift가 나오게 된 이유
- 비동기 작업의 간소화 : 비동기 작업(네트워크 , 사용자 입력 등)을 처리할때 콜백이나 델리게이트 패턴을 사용하는 것은 코드 복잡도를 증가시킨다. RxSwift는 이러한 비동기 작업을 Observable을 통해 간결하게 표현할 수 있다.
- 코드의 가독성 및 유지보수성 향상 : RxSwift를 사용하면 데이터 흐름을 명확하게 정의할 수 있어 코드의 가독성과 유지보수성이 향상된다.
- 함수형 프로그래밍의 장점 : RxSwift는 함수형 프로그래밍 패러다임을 따르기 때문에 부수 효과를 줄이고, 선언적 프로그래밍 스타일을 촉진한다.
RxSwift 기본 개념
- Observable : 데이터를 시간에 따라 비동기적으로 생성하는 스트림, Observable은 구독(subscribe)함으로써 데이터나 이벤트를 전달받을 수 있다.
- Observer : Observable을 구독하여 데이터를 수신하는 객체
- Operators : Observable에서 생성된 데이터를 변환하거나 필터링 하는데 사용되는 함수
- Schedulers : 코드가 실행될 스레드를 지정하는데 사용된다. 주로 메인 스레드에서 UI업데이트를 하거나 백그라운드 스레드에서 네트워크 작업을 처리할 때 사용된다.
네트워킹 작업 시 RxSwift 예시
pod 'RxSwift'
pod 'RxCocoa'
pod 'Alamofire'
이 예시에서는 이렇게 세가지 라이브러리를 사용할 예정이다. 나는 SPM을 사용하고 있어서 이 방법으로 추가하진 않을 예정이지만 정상적으로 작동하게끔 넣어주기만 하면 된다.
GitHub에서 사용자 목록을 가져온다고 가정하고 예시를 만들어보자
struct User: Decodable {
let id: Int
let login: String
let avatar_url: String
}
먼저 가져올 데이터 모델링을 정의한다.
import Alamofire
import RxSwift
class NetworkService {
func fetchUsers() -> Observable<[User]> {
return Observable.create { observer in
let request = AF.request("<https://api.github.com/users>")
.responseDecodable(of: [User].self) { response in
switch response.result {
case .success(let users):
observer.onNext(users)
observer.onCompleted()
case .failure(let error):
observer.onError(error)
}
}
return Disposables.create {
request.cancel()
}
}
}
}
NetworkService 클래스를 만들어 알라모파이어와 RxSwift를 활용해 API 데이터를 가져오는 작업을 실행한다.
이 과정을 통해 깃허브에서 데이터 모델에 있는 데이터를 가져온다고 보면된다.
다음으로 네트워크 요청 결과를 처리하고 이를 UI에 바인딩 할 ViewModel을 정의한다.
import RxSwift
import RxCocoa
class UsersViewModel {
let users: BehaviorRelay<[User]> = BehaviorRelay(value: [])
private let networkService = NetworkService()
private let disposeBag = DisposeBag()
func fetchUsers() {
networkService.fetchUsers()
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] users in
self?.users.accept(users)
}, onError: { error in
print("Error fetching users: \\(error)")
})
.disposed(by: disposeBag)
}
}
이렇게 구현한 VM을 하나하나 살펴보자
func fetchUsers() {
networkService.fetchUsers()
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] users in
self?.users.accept(users)
}, onError: { error in
print("Error fetching users: \\(error)")
})
.disposed(by: disposeBag)
}
networkService.fetchUsers() : 네트워크 요청을 Observable로 감싸서 반환한다.
.observe(on: MainScheduler.instance) : 결과를 메인 스레드에서 처리하도록 설정한다.
.subscribe(onNext:) : 네트워크 요청 결과를 구독하고, 성공 시 ‘users’ 속성을 업데이트 한다.
.disposed(by: disposeBag) : 메모리 관리를 위해 DisposeBag에 추가한다.
이렇게 VM을 구현했다면 VC에 바인딩 하면 된다.
import UIKit
import RxSwift
import RxCocoa
class UsersViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
private let viewModel = UsersViewModel()
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
bindViewModel()
viewModel.fetchUsers()
}
private func setupTableView() {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "UserCell")
}
private func bindViewModel() {
viewModel.users
.bind(to: tableView.rx.items(cellIdentifier: "UserCell")) { index, user, cell in
cell.textLabel?.text = user.login
}
.disposed(by: disposeBag)
}
}
VM 인스턴스를 통해서 UsersVM을 가져오고 VM에서 구현한 내용을 가져와 사용하면된다.
이 중에서 바인딩하는 과정을 자세하게 보자
private func bindViewModel() {
viewModel.users
.bind(to: tableView.rx.items(cellIdentifier: "UserCell")) { index, user, cell in
cell.textLabel?.text = user.login
}
.disposed(by: disposeBag)
}
viewModel.users.bind(to: tableView.rx.items(cellIdentifier:)) : VM의 users 속성을 테이블 뷰의 데이터 소스로 바인딩 한다.
이전에 사용했던 dataSource방식이 아닌 이렇게 RxSwift 방식을 사용해 넣어두면 데이터 변화에 따라 UI 업데이트가 자동으로 이뤄지게 된다.
아직 모든 내용을 다 이해할 수 있는 건 아니지만, 이전에 해왔던 방식을 조금 더 효율적으로 할 수 있다는 점이 매우 흥미로운 것 같다.
앞으로도 꾸준히 공부해보자
'◽️ 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 |
[SwiftUI,RxSwift] 데이터 모델링, 메인 UI 그리기 , DisposeBag , onNext , onAppear (0) | 2024.07.05 |