[Swift]RxSwift은 왜 쓰는걸까?

mmim·2022년 6월 27일
0

RxSwift가 생긴 이유가 뭘까
swift로 비동기 로직을 구현할 때 한번쯤은 아래와 같은 복잡한 코드를 경험해봤을 것이다.
비동기적 방법으로 통신을 하기 때문에 뒤늦게 그 결과로 가져오게 될 json을 외부로 전달할 방법이 없다.
때문에 completionHandler escaping 클로저를 사용하게 되고, 그 결과 코드가 복잡해지는 것이다.

func downloadJson(_ url: String, _ completion: @escaping (String?) -> Void) {
        DispatchQueue.global().async {
            // some code
            
            DispatchQueue.main.async {
                completion(json)
            }
        }
    }
    
func onLoad() {
	editView.text = ""
      
	downloadJson(MEMBER_LIST_URL) { json in
		self.editView.text = json
	}
}

만약에 4번 연속 비동기적인 작업이 필요하다면 아래와 같이 코드가 복잡해진다.
더불어서 에러처리, 특정 동작을 넣게된다면 이보다 훨씬 복잡해질 것이다.

func onLoad() {
	editView.text = ""
      
	downloadJson(MEMBER_LIST_URL) { json in
		self.editView.text = json
        
        downloadJson(MEMBER_LIST_URL) { json in
			self.editView.text = json
            
        	downloadJson(MEMBER_LIST_URL) { json in
				self.editView.text = json
                
                downloadJson(MEMBER_LIST_URL) { json in
					self.editView.text = json
                }
        	}
        }
	}
}

개발자들은 이 과정이 복잡하고 귀찮다고 생각하게 된다.
아래 코드처럼 나중에생기는데이터<String?> 라는 반환값을 갖도록하고 completionHandler 대신에 사용할 순 없을까? 만약 가능하다면 보는 것과 같이 매우 간결한 코드 작성이 가능할 것이다.

func downloadJson(_ url: String) -> 나중에생기는데이터<String?> {
        DispatchQueue.global().async {
            // some code
        }
    }
    
func onLoad() {
	editView.text = ""
    
    let json: 나중에생기는데이터<String?> = downloadJson(MEMBER_LIST_URL)
    json.나중에_데이터가_생기면_실행_메서드 { json in
    	self.editView.text = json
    }
}

아래 코드처럼 class 나중에생기는데이터 를 구현하는 것으로 비동기 동작으로 인해 나중에 생기는 데이터를 반환하여 사용할 수 있는 방법 구현이 가능하다.

class 나중에생기는데이터<T> {
    private let task: (@escaping (T) -> Void) -> Void
    
    init(task: @escaping (T) -> Void) -> Void) {
        self.task = task
    }
    
    func 나중에_데이터가_생기면_실행_메서드(_ f: @escaping (T) -> Void) {
        task(f)
    }
}

class ViewController {
	func downloadJson(_ url: String) -> 나중에생기는데이터<String?> {
        return 나중에생기는데이터() { f in
        	DispatchQueue.global().async {
        	    // json을 받아오는 some code
                f(json)
      	 	}
        }
        
    }
    
	func onLoad() {
		editView.text = ""
   		let json: 나중에생기는데이터<String?> = downloadJson(MEMBER_LIST_URL)
        
   		json.나중에_데이터가_생기면_실행_메서드 { json in
    		self.editView.text = json
    	}
	}
}

위와 같은 과정을 거쳐 좀더 쉽고 간결하게 비동기 로직을 구현하기 위한 고민을 했고, 그렇게 탄생한 유틸리티 중 하나가 RxSwift 이다.
위에서 언급한 코드를 RxSwift로 바꾼다면 아래와 같아진다.

class ViewController {
	// 나중에생기는데이터<String?> 타입은 Rx에 구현된 Observable<String?> 타입
	func downloadJson(_ url: String) -> Observable<String?> {
        return Observable.create() { f in
        	DispatchQueue.global().async {
        	    // json을 받아오는 some code
                f.onNext(json)
      	 	}
            return Disposables.create()
        }
    }
    
	func onLoad() {
		editView.text = ""
		// 나중에_데이터가_생기면_실행_메서드 -> subscribe
        // subscribe는 evrnt를 받고 각 event별로 로직을 구현하면 된다.
		downloadJson(MEMBER_LIST_URL)
   			.subscribe { event in
            	switch event {
            	case let .next(json):
    				self.editView.text = json
                case .completed:
                case .error:
                	break
    			}
        	}
	}
}

이처럼 비동기 로직의 completionHandler 대신에 반환값을 사용하고,
Observable create() / Disposables.create() / subscribe 등 좀더 다양한 기능을 더한 것이 RxSwift이다.

RxSwift를 이해하는 것에 아래 두가지 방법이 큰 도움이 된다.

  1. 비동기로 생기는 데이터를 Observable로 감싸서 반환하는 방법
  2. Observable로 오는 데이터를 받아서 처리하는 방법
profile
예비 iOS 개발자의 기록

0개의 댓글