티스토리 뷰

스위프트

[Swift] - Rxswift 예제로 이해해보기

강철곰탱이 2024. 11. 2. 18:45

 

예제를 알아보기 전, 일단 rxswift를 설치해줘야 한다.

 

 

GitHub - ReactiveX/RxSwift: Reactive Programming in Swift

Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.

github.com

 

 

예제로 간단하게 사용자 정보를 조회하는 로직을 구현해보고자 한다.

api 연동은 안 되어있어서 연동된 것처럼 작동하도록 만들어보자.

 

📖 목차

1. View 구현
2. DispatchQueue를 사용해 ViewModel 구현
3. RxSwift를 사용해 ViewModel 구현
4. DispatchQueue와 RxSwift 비교
5. 기능 추가해서 비교해보기

 


1. View 구현

 

사용자 정보를 조회하는 버튼을 만들고 버튼을 클릭하면 받아온 유저 정보를 보여주는 view를 만들어보자.

 

  • 사용자 정보 조회 버튼
  • 사용자 정보 보여지기 전 보여줄 ProgressView
  • 사용자 정보 보여줄 VStack

 

 

viewModel의 UserState로 데이터를 받아왔는지 판단하고 그 여부로 view에 데이터를 어떤 걸 보여줄지 정한다.

 

enum UserState {
    case initial // 초기 상태
    case loading // 로딩 상태
    case loaded(User) // 데이터가 성공적으로 로드된 상태 (User 모델 포함)
    case error(String) // 에러 상태 (에러 메시지 포함)
}

 

구현한 view 구조는 다음과 같다.

 

struct ContentView: View {
    @StateObject private var viewModel = UserViewModel()
    
    var body: some View {
        VStack(spacing: 20) {
            switch viewModel.userState {
            case .initial:
                Text("사용자 정보를 조회하려면 아래 버튼 클릭")
                
            case .loading:
                ProgressView()
                
            case .loaded(let user):
                VStack(alignment: .leading, spacing: 12) {
                    Text("이름: \(user.name)")
                    Text("아이디: \(user.username)")
                    Text("번호: \(user.phone)")
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding()
                .background(Color.gray.opacity(0.1))
                .cornerRadius(10)
                
            case .error(let message):
                Text(message)
                    .foregroundColor(.red)
            }
            
            Button(action: {
                viewModel.fetchUser()
            }) {
                Text("사용자 정보 조회")
                    .foregroundColor(.white)
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(Color.blue)
                    .cornerRadius(10)
            }
        }
        .padding()
    }
}

 

 


2. DispatchQueue를 사용해 ViewModel 구현

 

 

플로우는 다음과 같다.

 

  1. 유저가 유저 정보 조회 화면에 들어온다. (initial 상태)
  2. 유저가 유저 정보 조회 버튼을 클릭한다. 클릭 후, 2초동안 ProgressView가 보여진다.(loading 상태)
  3. 2초가 지난 후 네트워크 요청이 성공여부에 따라 loaded와 error로 상태가 바뀐다.
    • (loaded 상태) 유저 정보가 반환되고, 뷰에 해당 정보가 보여진다.
    • (error 상태) 오류가 반환되고, 뷰에 해당 정보가 보여진다.

 

api 연동을 하지 못했기 때문에 DispatchQueue로 2초 지연시간이 발생하도록 하였다.

 

// 2초 지연 후 더미 데이터를 반환하는 비동기 작업
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
    ...
}

 

네트워크 요청 성공 여부 랜덤으로 처리하였고, 성공하면 더미 데이터로 유저 정보를 반환하도록, 실패하면 오류를 반환하도록 처리했다.

 

  DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
    // 네트워크 요청 성공 여부 랜덤으로 반환
    let isSuccess = Bool.random()
    let result: Result<User, Error> = isSuccess
     ? .success(User(id: 0, name: "abc", username: "abc id", phone: "010-1234-5678"))
     : .failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."]))
}

 

 

🔎 만약 Result를 모르겠다면 참고

 

더보기

Result는 Swift에서 제공하는 열거형(enum)으로, 비동기 작업이나 오류가 발생할 가능성이 있는 작업의 성공 또는 실패를 표현하는데 사용된다. 두 가지 상태를 가지며, 각 상태는 success와 failure로 나타낸다.

 

이런식으로 두가지 상태에 따라 처리하고 위에서 Result<User, Error>를 처리한 이유도 Result 반환 형식때문에 그렇다.

enum Result<Success, Failure: Error> {
    case success(Success)
    case failure(Failure)
}
let result: Result<User, Error>
switch result {
case .success(let user):
    print("성공: \(user)")
case .failure(let error):
    print("실패: \(error.localizedDescription)")
}

 

🔎  만약 NSError를 모르겠다면 참고

 

더보기

NSError는 Swift와 Objective-C에서 사용되는 에러 정보를 포함하는 객체로, 오류의 도메인, 코드, 사용자 정보 등을 저장할 수 있다.

 

다음과 같이 사용하며 Error타입을 사용자가 정의해서 반환하고자 하는 경우 사용한다.

let error = NSError(
    domain: "NetworkError",               // 에러 도메인
    code: -1,                             // 에러 코드
    userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."] // 사용자에게 보여질 오류 정보
)

 

위에서 사용한 Result<User, Error>에서 오류가 발생했을 때 Error 타입으로 반환해야되기 때문에 NSError를 사용했다.

 

이제 성공과 실패 여부에 따라 UserState를 다르게 처리해주면 끝이난다.

 

 func fetchUser() {
    userState = .loading // 조회 시작 시 상태를 로딩으로 설정

    // 2초 지연 후 더미 데이터를 반환하는 비동기 작업
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
        // 네트워크 요청 성공 여부 랜덤으로 반환
        ...

        switch result {
        case .success(let user):
            self?.userState = .loaded(user) // 데이터 로드 성공 시 상태를 loaded로 업데이트

        case .failure:
            self?.userState = .error("error 발생") // 에러 발생 시 상태를 error로 설정
        }
    }
}

 

 

  • 최종코드
// ViewModel 클래스
class UserViewModel: ObservableObject {
    @Published var userState: UserState = .initial
    
     func fetchUser() {
        userState = .loading // 조회 시작 시 상태를 로딩으로 설정

        // 2초 지연 후 더미 데이터를 반환하는 비동기 작업
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
            // 네트워크 요청 성공 여부 랜덤으로 반환
            let isSuccess = Bool.random()
            let result: Result<User, Error> = isSuccess
             ? .success(User(id: 0, name: "abc", username: "abc id", phone: "010-1234-5678"))
             : .failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."]))

            switch result {
            case .success(let user):
                self?.userState = .loaded(user) // 데이터 로드 성공 시 상태를 loaded로 업데이트

            case .failure:
                self?.userState = .error("error 발생") // 에러 발생 시 상태를 error로 설정
            }
        }
    }
}

 


3. RxSwift를 사용해 ViewModel 구현

 

이제 RxSwift를 사용해서 ViewModel을 구현해보면서 DispatchQueue를 사용한 경우와 뭐가 다른지 확인해 보자.

 

RxSwift에서 중요한 3가지가 있다.

 

  • Observer(관찰자)
  • Observable(관측 가능한)
  • Subscribe(구독)

 

이 3가지의 관계는 "관찰자는 관측 가능한 것을 구독한다."이다.

이를 좀 더 자세히 설명하면, "관찰자는 관측 가능한 것이 방출하는 이벤트에 반응한다."라고 할 수 있다.

 

구독은 Observer와 Observable을 연결해주는 역할을 하며 계속 연결하는 건 메모리가 소모되고 있음을 의미한다.

그래서 연결을 해제하는 로직도 필요한데 이것을 해주는게 dispose이다.

 

이를 위해 DisposeBag를 사용해 메모리 해제까지 완료하도록 구현해보자.

 

 

 

Observable 

 

 

Observabel.just를 사용해서 User 타입의 데이터를 방출하고 완료처리하도록 해보자.

just는 "한개"의 항목만 방출하고 바로 dispose 되어버리기 때문에 사용자 정보만 반환하는 현재 예제에 적합해서 사용하였다.

 

Observable.just(User(
    id: 0,
    name: "abc",
    username: "abc id",
    phone: "010-1234-5678"
))
.delay(.seconds(2), scheduler: MainScheduler.instance)//2초 지연시간
.observe(on: MainScheduler.instance)

 

 

delay를 사용하여 2초 동안 지연된 후에 User 데이터를 방출하도록 설정했다.

또한 2초 지연시간이 있는 동안 ui에 progressView를 보여줘야 하기 때문에 ui 작업 때문에 MainScheduler.instance를 사용해 메인 스레드에서 실행되도록 하였다.

 

observe(on:)연산자는 데이터가 방출된 이후에 실행되는 모든 작업의 스레드를 지정한다.

받은 User데이터도 View에 보여줘야 하기 때문에 observe(on: MainScheduler.instance)로 설정해서 이후의 subscribe 작업들이 메인 스레드에서 실행되도록 했다.

 

 

Subscribe

 

 

subscribe는 Observable이 방출하는 값을 받아서 처리하는 부분이다. 여기서는 onNext와 onError를 사용해 각각 성공과 에러 상황을 다룬다.

 

  • onNext: Observable이 성공적으로 값을 방출했을 때 실행되는 클로저. user 데이터를 받아서 userState를 .loaded(user)로 업데이트한다.
  • onError: 에러가 발생했을 때 실행되는 클로저. 이 예제에서는 단순히 에러 메시지를 설정해 userState를 .error("error 발생")로 업데이트한다.

 

 

DisposeBag

 

 

 

DisposeBag은 Observable의 구독을 관리해 메모리 누수를 방지하는 역할을 한다.

disposed(by:)를 사용해서 구독을 disposeBag에 저장하면, disposeBag이 해제될 때 그 안에 저장된 모든 구독이 자동으로 해제(dispose)된다.

 

=> 그럼 구독을 하나씩 해제할 필요 없이, 특정 시점에서 DisposeBag만 해제되면 관련 구독이 모두 해제되므로 메모리 관리를 훨씬 간편하게 할 수 있다. 

특히, 여러 개의 Observable을 구독하고 있을 때 유용하다. 수동으로 하나씩 구독을 해제하는 경우 코드의 가독성이 떨어지고, 실수로 구독을 빠뜨리는 경우 메모리 누수가 발생할 수 있기 때문이다.

 

 .disposed(by: disposeBag)

 

 

 


 

 

  • 최종 코드
class UserViewModel: ObservableObject {
    private let disposeBag = DisposeBag()
    @Published var userState: UserState = .initial

    func fetchUser() {
        userState = .loading // 조회 시작 시 상태를 로딩으로 설정
        
        // 더미 데이터를 비동기로 반환하는 Observable
        Observable.just(User(
            id: 0,
            name: "abc",
            username: "abc id",
            phone: "010-1234-5678"
        ))
        .delay(.seconds(2), scheduler: MainScheduler.instance) // 네트워크 통신
        .observe(on: MainScheduler.instance)
        .subscribe(
            onNext: { [weak self] user in
                self?.userState = .loaded(user)
            },
            onError: { _ in
                self.userState = .error("error 발생")
            }
        )
        .disposed(by: disposeBag)
    }
}

 

여기까지 구현하면 View에는 버튼을 클릭하면 계속 성공처리가 되어 유저정보가 나오게 된다.

왜냐하면 just를 사용해서 계속 User 데이터를 반환하기 때문에 error가 발생할 수가 없다.

 

 

성공/실패에 따라 분기처리 

 

 

성공 여부를 let success = Bool.random()를 사용해서 랜덤으로 처리하도록 했다.

 

성공과 실패 여부를 observable이 알려줘야하기 때문에 just가 아니라 create를 사용하였다.

just까지 겨우 이해했는데 create는 또 뭘까..?

 

just는 하나의 데이터 타입만 반환할 수 있기 때문에 계속 성공을 처리할 수 밖에 없었다.

create는 Observer의 onNext, onCompleted, onError 메서드를 직접 호출할 수 있어서 성공 여부에 따라 다르게 처리가 가능하다.

 

아하 create를 사용하면 onNext나 onError와 같은 메서드를 직접 호출할 수 있으니까 성공 여부를 처리할 수 있겠구나~

사용해 보자.

 

 Observable<User>.create { observer in
    // 랜덤으로 성공 또는 실패 결정
    let success = Bool.random() // 무작위로 true 또는 false 반환

    if success {
        // 성공 시 더미 데이터 반환
        let user = User(
            id: 0,
            name: "abc",
            username: "abc id",
            phone: "010-1234-5678"
        )
        observer.onNext(user)
        observer.onCompleted() // 데이터 전송 완료
    } else {
        // 실패 시 에러 발생
        let error = NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."])
        observer.onError(error) // 에러 전송
    }

    return Disposables.create() // 리소스 해제용
}

 

위와 같이 처리하여 성공한 경우 User 데이터를 반환하고, onNext와 onCompleted를 호출한다.

 

  • onNext(user): 성공적으로 사용자 데이터를 수신했을 때 호출. 여기서는 User 객체를 방출한다.
  • onCompleted(): 데이터 방출이 완료되었을 때 호출. 추가로 더 이상 데이터가 없다는 것을 나타낸다.

 

실패한 경우 onError를 호출하여 에러를 반환한다.

  • onError(error): 오류가 발생했을 때 호출. 여기서는 NSError 객체를 통해 에러 메시지를 전달한다.

 

 

여기까지 하고 delay와 observe, .. 등 다른 메서드들은 동일하게 구현하면 된다.

그럼 성공과 실패가 랜덤으로 나오면서 view에도 데이터가 잘 나오는 걸 확인할 수 있다.

 

  • 최종 코드
func fetchUser() {
    userState = .loading // 조회 시작 시 상태를 로딩으로 설정

    Observable<User>.create { observer in
        // 랜덤으로 성공 또는 실패 결정
        let success = Bool.random() // 무작위로 true 또는 false 반환

        if success {
            // 성공 시 더미 데이터 반환
            let user = User(
                id: 0,
                name: "abc",
                username: "abc id",
                phone: "010-1234-5678"
            )
            observer.onNext(user)
            observer.onCompleted() // 데이터 전송 완료
        } else {
            // 실패 시 에러 발생
            let error = NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."])
            observer.onError(error) // 에러 전송
        }

        return Disposables.create() // 리소스 해제용
    }
    .delay(.seconds(2), scheduler: MainScheduler.instance) 
    .observe(on: MainScheduler.instance) 
    .subscribe(
        onNext: { [weak self] user in
            self?.userState = .loaded(user) // 데이터 로드 성공 시 상태를 loaded로 업데이트
        },
        onError: { [weak self] error in
            self?.userState = .error(error.localizedDescription) // 에러 발생 시 상태를 error로 설정
        }
    )
    .disposed(by: disposeBag) 
}

 


4. DispatchQueue와 RxSwift 비교

 

이렇게 같은 유저 정보 조회 기능을 DispatchQueue와 RxSwift를 사용해서 구현해보았는데, 이 둘의 차이점이 뭘까??

 

성공 여부 처리하는 방식의 차이를 보자.

 

  • DispatchQueue
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
    let result: Result<User, Error> = isSuccess
     ? .success(User(id: 0, name: "abc", username: "abc id", phone: "010-1234-5678"))
     : .failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."]))
     ...
}

 

  • RxSwift
Observable<User>.create { observer in
    if success {
        // 성공 시 더미 데이터 반환
        let user = User(
            id: 0,
            name: "abc",
            username: "abc id",
            phone: "010-1234-5678"
        )
        observer.onNext(user)
        observer.onCompleted() // 데이터 전송 완료
    } else {
        // 실패 시 에러 발생
        let error = NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."])
        observer.onError(error) // 에러 전송
    }
    ...
}

 

 

이렇게 비교하면 DispatchQueue를 사용하는 것이 더 간단해보인다. 이는 유저 정보 조회라는 간단한 비동기 작업을 처리하는 예제이기 때문이다.

 

만약 복잡한 비동기 작업이 있는 경우 DispatchQueue는 다음과 같은 문제가 있다.

 

1. 상태 관리의 복잡성

  • 여러 비동기 작업이 동시에 발생할 때, 각 작업의 상태를 관리하기가 어려워진다. 예를 들어, 여러 DispatchQueue를 사용해 비동기 요청을 보내고, 그 결과에 따라 UI를 업데이트하려고 할 때, 각 요청의 성공/실패 여부를 추적해야 한다.
    상태를 적절하게 업데이트하려면 여러 곳에서 코드가 분산되어 관리해야 하고, 이로 인해 버그가 발생할 가능성이 높아진다.

 

2. 에러 처리의 비효율성

  • 각 비동기 작업에서 에러를 처리할 때마다 별도의 에러 처리 로직을 구현해야 한다. 요청이 실패할 경우, 각 스레드에서 에러를 어떻게 처리할지 결정해야 하는데, 이렇게 되면 중복 코드가 생기거나 일관된 에러 처리 전략을 유지하기가 어려워질 수 있다.

 

3. 콜백 지옥 

  • 여러 개의 비동기 작업이 서로 종속되는 경우, 작업이 끝나면 다음 작업을 시작하는 식으로 콜백을 중첩해야 한다. 이렇게 되면 코드가 깊게 중첩되고, 가독성이 떨어지며 디버깅하기 어려워지는 현상이 발생한다.

 

=> 이런 이유들로 인해, DispatchQueue를 사용해 복잡한 비동기 작업을 처리할 때는 코드가 난잡해지기 쉽고,  명시적인 에러 처리가 필요해서 관리하기 어려워질 수 있다. 반면, RxSwift는 이벤트 흐름에 따라 에러를 처리할 수 있어 더 유연하다.

 

 


5. 기능 추가해서 비교해보기

 

 

사용자 이름을 수정하는 기능을 추가해보자!

view는 다음과 같이 바뀌게 된다.

 

 

  • 코드
더보기
struct ContentView: View {
    @StateObject private var viewModel = UserViewModel()
    @State private var newName: String = "" // 새 이름을 저장할 상태 변수
    
    var body: some View {
        VStack(spacing: 20) {
            switch viewModel.userState {
            case .initial:
                Text("사용자 정보를 조회하려면 아래 버튼 클릭")
                
            case .loading:
                ProgressView()
                
            case .loaded(let user):
                VStack(alignment: .leading, spacing: 12) {
                    Text("이름: \(user.name)")
                    Text("아이디: \(user.username)")
                    Text("번호: \(user.phone)")
                    
                    // 이름 변경 입력 필드
                    TextField("새 이름 입력", text: $newName)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    
                    // 이름 변경 버튼
                    Button(action: {
                        viewModel.changeUserName(to: newName) // 새 이름으로 변경
                    }) {
                        Text("이름 변경")
                            .foregroundColor(.white)
                            .padding()
                            .frame(maxWidth: .infinity)
                            .background(Color.green)
                            .cornerRadius(10)
                    }
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding()
                .background(Color.gray.opacity(0.1))
                .cornerRadius(10)
                
            case .error(let message):
                Text(message)
                    .foregroundColor(.red)
            }
            
            Button(action: {
                viewModel.fetchUser()
                newName = ""
            }) {
                Text("사용자 정보 조회")
                    .foregroundColor(.white)
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(Color.blue)
                    .cornerRadius(10)
            }
        }
        .padding()
    }
}

 

다음과 같이 changeUserName 함수를 만들어서 현재 사용자 정보(currentUser)의 이름을 매개변수로 받은 이름으로 변경하도록 한다.

DispatchQueue와 RxSwift 둘 다 changeUserName 함수를 사용해 이름 변경을 수행한다.

class UserViewModel: ObservableObject {

    @Published private var currentUser: User? // 사용자 정보를 저장할 변수
    ...
    
    // 새 이름으로 사용자 이름 변경
    func changeUserName(to newName: String) {
        guard var user = currentUser, !newName.isEmpty else { return } // 현재 사용자 정보가 없거나 빈 이름이면 무시
        user = user.changeName(to: newName)
        currentUser = user // 현재 사용자 정보를 업데이트
        userState = .loaded(user) // 상태 업데이트
    }
}

 

이름 변경 후 다시 조회했을 때도 변경된 이름으로 잘 조회하기 위해 fetchUser()를 수정해보자.

 

DispatchQueue

 

 

currentUser에 값이 있다면 한번 조회한 데이터이니까 다시 User정보를 받아오는게 아니라 currentUser를 보여준다.

 

func fetchUser() {
    userState = .loading

    DispatchQueue.global().asyncAfter(deadline: .now() + 2) { [weak self] in
        let success = Bool.random()

        DispatchQueue.main.async {
            if success {
                if let user = self?.currentUser {
                    // 기존의 currentUser 정보가 있을 경우 이를 반환
                    self?.userState = .loaded(user)
                } else {
                    // 새로운 User 정보를 생성하여 반환
                    let user = User(
                        id: 0,
                        name: "abc",
                        username: "abc id",
                        phone: "010-1234-5678"
                    )
                    self?.currentUser = user
                    self?.userState = .loaded(user)
                }
            } else {
                // 실패 시 에러 발생
                let errorMessage = "네트워크 오류가 발생했습니다."
                self?.userState = .error(errorMessage)
            }
        }
    }
}

 

DispatchQueue는 currentUser 존재 여부에 따라서 실패와 성공을 판단하는 단순한 구조를 가지고 있다.

어떤 데이터나 에러에 대해 구독하고 있지 않아서 반응형에 적합하지 않다.

 

 

RxSwift

 


currentUser에 값이 있다면 한번 조회한 데이터이니까 다시 User정보를 받아오는게 아니라 currentUser를 보여준다.

 

func fetchUser() {
    userState = .loading

    Observable<User>.create { observer in
        let success = Bool.random()

        if success {
            if let user = self.currentUser {
                observer.onNext(user) // currentUser의 정보를 반환
                observer.onCompleted()
            } else{
                let user = User(
                    id: 0,
                    name: "abc",
                    username: "abc id",
                    phone: "010-1234-5678"
                )
                observer.onNext(user)
                observer.onCompleted()
            }
        } else {
            let error = NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "네트워크 오류가 발생했습니다."])
            observer.onError(error)
        }

        return Disposables.create()
    }
    .delay(.seconds(2), scheduler: MainScheduler.instance)
    .observe(on: MainScheduler.instance)
    .subscribe(
        onNext: { [weak self] user in
            self?.currentUser = user // 사용자 정보를 저장
            self?.userState = .loaded(user)
        },
        onError: { [weak self] error in
            self?.userState = .error(error.localizedDescription)
        }
    )
    .disposed(by: disposeBag)
}

 

단순히 성공/실패만 판단하는 Dispatch Queue와는 달리 onNext, onCompleted, onError등을 사용해서 반응형으로 처리할 수 있다. 

 

 

RxSwift 코드에서는 비동기 흐름과 에러 처리를 구독 형태로 관리할 수 있어 반응형으로 구성되지만 복잡해진다. 그래서 간단한 비동기 작업을 처리하는 경우라면 Dispatch Queue를 사용하는게 더 좋을 것 같다.

 

 

  RxSwift DispatchQueue
주요 목적 데이터 흐름 관리, 반응형 프로그래밍 비동기 작업 실행, 스레드 관리
데이터 흐름 관리 가능 (Observable/Observer로 상태 관리) 불가능 (단순히 작업을 큐에 넣어 실행)
비동기 작업 처리 가능 (observeOn, subscribeOn으로 설정) 가능 (async로 비동기 작업 설정)

 


결론

 

 

비동기 처리 방식은 DispatchQueue뿐만 아니라 Notification Center, async/await등과 같이 다양하게 있어서 이걸 무분별하게 사용할 경우 통합하기 어려운 문제가 발생할 수 있다.

반면 RxSwift를 사용하면, 여러 비동기 작업에 각자 다른 처리방식을 사용하지 않고 RxSwift를 사용하도록 통일하여 일관성있게 처리할 수 있다.

 

비록 RxSwift를 익히는 데 시간이 걸릴 수 있지만, 추후 복잡한 비동기 작업을 처리하거나 반응형 프로그래밍이 필요한 경우 RxSwift를 사용하는 것이 오류를 줄이는 데 큰 도움이 될 것이라고 생각한다.

 

그래서 결국 프로젝트 규모에 따라 적절하게 사용하는게 좋을 것 같다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함