iOS/RxSwift

Alamofire + RxSwift + MVVM

HJ39 2023. 3. 5. 21:35

우선 RxSwift는 Return을 통해 데이터를 가지고 온다.

 

Rxswift를 사용하기 전에는 Alamofire으로 통신하는 경우 @escaping을 통해 데이터를 viewModel로 가져온 뒤

같은 방법으로 View로 데이터를 전달하였다.

해당 방법을 사용하면 코드가 복잡해지고 직관적이지 못하다는 단점이 있다.

(저는 그렇더라고요..ㅎ)

 

그래서!

 

우선 먼저 전체적인 흐름을 설명하자면

  1. Alamofire post 통신을 한 후 Observable을 이용하여 ViewModel 데이터를 가져온다.
  2. 가져온 데이터를 다시 Alamofire get 통신을 한 후 Observable을 이용하여 ViewModel 데이터를 가져온다.
  3. ViewModel로 가져온 데이터를 Observable을 이용하여 View로 보낸다.

 

□ ViewModel

class RxViewModel{
    let disposeBag = DisposeBag()
    
    func binding() -> Observable<Model>{
        return Observable<Model>.create(){ observer in
            RxService.escape.postData()
                .subscribe(onNext: { data in
                    RxService.escape.getData(id: data).subscribe(onNext: { info in
                        print(info)
                        observer.onNext(info)
                    })
                    .disposed(by: self.disposeBag)
                })
                .disposed(by: self.disposeBag)
            
            return Disposables.create()
        }
    }
}

→ Return으로 Observable로 하면 데이터를 비동기적으로 처리하여 view에 보낼 수 있다.

→ RxService.escape.postData()를 통해 아래 post 통신을 실행한다. 

→ post 통신을 실행한 뒤 observable로 전달받은 데이터를 subscribe 하여 받는다.

→ 받은 데이터를 다시 Alamofire get 통신을 한다.

→ 같은 방법으로 진행한다.

 

 

□ Alamofire post 통신

func postData() -> Observable<Int>{
        let url = "http://\(self.localhost)/api/members"
        let body = ["githubId" : "HJ39"]
        
        return Observable<Int>.create(){ observer in
            AF.request(url,
                       method: .post,
                       parameters: body,
                       encoding: JSONEncoding.default,
                       headers: ["Content-type": "application/json"])
            .validate(statusCode: 200..<201)
            .responseDecodable(of: Int.self) { response in
                switch response.result{
                case .success(let data):
                    observer.onNext(data)
                case .failure(let error):
                    print(error)
                }
            }
            return Disposables.create()
        }
    }

→ url의 localhost는 서버와 연결하기 위해 서버의 ip를 넣으면 된다.

→ ViewModel에서 해당 함수를 실행하면 네트워크 통신 후 받은 데이터를 전달하게 된다.

→ Observable <Int>. create()를 통해 Observable을 생성한다. (인자로 escaping closure가 전달된다.)

→ Disposables를 통해 위에서 생성한 Observable을 메모리 상에서 삭제한다.

 

□ Alamofire get 통신

func getData(id:Int) -> Observable<Model>{
        let url = "http://\(self.localhost)/api/members/\(id)"
        
        return Observable<Model>.create(){ observe in
            AF.request(url,
                       method: .get,
                       headers: ["Content-type": "application/json"])
            .validate(statusCode: 200..<201)
            .responseDecodable(of: DecodingModel.self) { response in
                switch response.result{
                case .success(let data):
                    observe.onNext(Model(id: data.id ?? 0,
                                     name: data.name ?? "unknown",
                                     githubId: data.githubId ?? "",
                                     commits: data.commits ?? 0,
                                     tier: data.tier ?? "",
                                     authStep: data.authStep ?? "",
                                     profileImage: data.profileImage ?? "",
                                     rank: data.rank ?? 0,
                                     tokenAmount: data.tokenAmount ?? 0))
                case .failure(let error):
                    print(error)
                }
            }
            
            return Disposables.create()
        }
    }

→ post통신과 크게 다른 점이 없다.

 

 

□ ViewController

class ViewController: UIViewController {
    @IBOutlet weak var lablel1: UILabel!
    let rxViewModel = RxViewModel()
    let dispoesBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bindingData()
    }
    
    func bindingData(){
        rxViewModel.binding().subscribe(onNext: { info in
            guard let data = info.githubId else {return}
            self.lablel1.text = "\(data)"
        })
        .disposed(by: dispoesBag)
    }
}

→ bindingData()를 실행한 후 데이터가 들어오면 리턴되어 lablel1이 변경되게 했다.

 

MVVM 패턴 적용하기가 너무 어렵다..ㅠ

 

# 참고한 사이트

  1. https://borabong.tistory.com/19
  2. https://vandijk.tistory.com/21

'iOS > RxSwift' 카테고리의 다른 글

RxSwift 사용  (0) 2023.01.14