apple/UIKit & ReactiveX

[iOS] RxStarscream 사용법 총정리!

lgvv 2022. 1. 12. 14:22

✅ 이번 시간에는 RxStarscream에 대해서 알아볼 예정이야.

 

우선 RxStarscream란 무엇인지 알아봐야겠지?

 

https://github.com/RxSwiftCommunity/RxStarscream

 

GitHub - RxSwiftCommunity/RxStarscream: A lightweight extension to subscribe Starscream websocket events with RxSwift

A lightweight extension to subscribe Starscream websocket events with RxSwift - GitHub - RxSwiftCommunity/RxStarscream: A lightweight extension to subscribe Starscream websocket events with RxSwift

github.com

 

RxStarScream은 위에 사이트를 가면 자세히 볼 수 있어.

WebSocket을 사용한다고 하면 주로 Starscream을 사용하는데 이걸 Rx로 제공해줘서 쉽게 사용할 수 있는 도구야. 

사실 Starscream을 가지고 Proxy로 감싸서 사용할 수도 있겠지만... 

이 과정이 생각보다 많이 까다로운 과정이라서 이건 나중에 따로 포스팅하도록 할게.

 

✅ 사전준비

 1. webSocket을 사용할 수 있는 서버? 

   -> 저는 개인적으로 WebSocket을 사용할 수 있는 서버가 있어서 그걸 이용했습니다! 

 없으신 분들은 직접 찾아보셔야 해서 ㅠㅠ 흐름이라도 알고가셔요!

 

✅ RxStarScream.swift

import Foundation

import Starscream
import RxStarscream
import SnapKit
import Then
import RxCocoa
import RxSwift

class RxStarScream: UIViewController {
    
    var bag = DisposeBag()
    private var webSocket: WebSocket!
    private var reqData: String = "{\n\"type\": \"staff\",\n\"content\": \"홍길동\"\n}" // 서버에 요청할 임시 요청 데이터
    
    private let writeSubject = PublishSubject<String>()
    
    private lazy var loadBtn = UIButton().then {
        $0.setTitle("load Button", for: .normal)
        $0.backgroundColor = .blue
    }
    
    private lazy var loadLabel = UILabel().then {
        $0.text = "자 과연 여기에 값을 넣을 수 있을까요?"
        $0.backgroundColor = .red
        $0.textAlignment = .center
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setConstraints()
        
        connect() // 1. webSocket 서버와 연결
        setBinding()
    }
    
    private func setBinding() {
    
    	// 3. 버튼을 탭하면 sendMessage 함수 호출
        loadBtn.rx.tap
            .debug("tap")
            .bind { [weak self] in
                self?.sendMessage(message: self!.reqData)
            }
            .disposed(by: bag)
        
        // 5. 웹 소켓을 통해 응답이 왔을때 rx로 처리하는 로직
        webSocket.rx.response
            .bind { [self] response in
                switch response {
                case .connected:
                    print("connected")
                case .disconnected (let _):
                    print("DisConnected")
                case .message(let msg):
                    print("msg \(msg)")
                    writeSubject.onNext(msg) // 5-1. 내려온 데이터를 subject로 넘기기
                    // TODO: 여기서 decoding을 처리한 후 subject로 보내도 좋습니다!
                case .data(let data):
                    print("data \(data)")
                case .pong:
                    print("pong")
                default:
                    print("default")
                }
            }.disposed(by: bag)
        
        // 6. 서브젝트를 UILabel에서 구독해서 처리
        writeSubject.asObservable()
            .bind(to: loadLabel.rx.text)
            .disposed(by: bag)
        
    }
}

extension RxStarScream {
    
    // 4. 웹 소켓 서버에 write 
    fileprivate func sendMessage(message: String) {
        webSocket.write(string: message) // 4-1. 웹소켓 서버에 request 데이터 전달
        writeSubject.onNext("SENT: \(message)") // 4-2. 서브젝트에 request 데이터 전달
        print("message sendMessage\n\(message)") // 4-3. 어떤 메시지 보냈는지 확인
    }
    
    // 2. 웹 소켓 서버와 연결하는 코드
    func connect() {
        print("connect function")
        let url = "{YOUR WEB SOCKET AVAIABLE SERVER}"
        var request = URLRequest(url: URL(string: url)!)
        
        request.addValue("{YOUR SERVER}", forHTTPHeaderField: "Origin") // HTTPUpgrade error 발생 시 넣어주면 됩니다.
        
        request.timeoutInterval = 10
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        
        webSocket = WebSocket(request: request)
        webSocket.connect()
    }
    
    func disconnect() {
        webSocket.disconnect()
    }
    
}


extension RxStarScream {
    private func setupViews() {
        [loadBtn, loadLabel].forEach {
            view.addSubview($0)
        }
    }
    
    private func setConstraints() {
        loadBtn.snp.makeConstraints {
            $0.top.left.right.equalToSuperview()
            $0.bottom.equalToSuperview().offset(-100)
        }
        
        loadLabel.snp.makeConstraints {
            $0.top.equalTo(loadBtn.snp.bottom)
            $0.left.right.bottom.equalToSuperview()
        }
    }
}

위에 숫자를 넣어서 데이터의 흐름이 어떻게 되는지 알 수 있게 해두었으니까, 꼭 확인해보기!

 

다음 포스팅은 아마 WebSocket을 오리지널 하게 사용하는 방법에 대해서 알아볼 예정이야.