Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- uiscrollview
- tableView
- SWIFT
- swift documentation
- ios
- 리팩토링
- Refactoring
- 스위프트
- RxCocoa
- HIG
- UICollectionView
- 클린 코드
- 리펙토링
- ribs
- collectionview
- Xcode
- Human interface guide
- 리펙터링
- Observable
- Clean Code
- 애니메이션
- UITextView
- clean architecture
- Protocol
- MVVM
- swiftUI
- rxswift
- map
- uitableview
- combine
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] RxSwift로 PingPong 로직 구현 방법 (핑퐁 로직, timer) 본문
핑퐁 로직
- PingPong을 사용하는 케이스는 일반적으로 웹소켓에서 사용
- 앱에서 서버에게 ping을 보내고, 서버로부터 pong을 받는 로직
- 만약 서버로부터 pong이 앱에서 설정한 특정 시간안에 안오면 lost connection으로 판단
- 주의할점
- 앱에서 서버에서 ping을 보낼때 throttle 적용 (만약 pong이 올때마다 ping을 날리면 짧은순간에 수많은 통신이 이루어짐)
핑퐁 구현 아이디어
- ping을 보내는 부분
- 1) API.requestPing 수행 -> response를 받으면 다시 ping을 보내는 코드를 구현
- 2) 서버에ping을 보낼땐 항상 timer를 사용하여 시간을 체크하고 타이머가 다 된 경우, completion 처리를 수행
- 타이머는 Swift에서 제공하는 Timer를 사용하지 않고 Observable<Int>.timer(_:scheduler:)를 사용하여 간편하게 구현
- Swift에서 제공하는 Timer를 사용하면 deinit할때도 timer를 따로 invalidate()시켜줘야 하는 코드가 들어가므로 번거로움
- Observable의 timer와 disposeBag을 적절히 사용하면 매우 편리하게 구현이 가능
핑퐁 구현에 사용한 라이브러리
핑퐁 구현
- 사용하는 쪽
- PingPong()이라는 인스턴스를 이용하여 runPingPong에 closure에 인터넷 연결이 끊긴 경우, completion 처리를 넣어서 사용
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
var pingPong: PingPong?
override func viewDidLoad() {
super.viewDidLoad()
self.pingPong = PingPong()
self.pingPong?.runPingPong {
print("lost connection")
}
}
}
- 예제로 사용할 API 구현
enum API {
static func requestPing() -> Observable<Int> {
.create { observer -> Disposable in
print("send ping")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
observer.onNext(Int.random(in: 0...10))
}
return Disposables.create()
}
}
}
- PingPong 클래스 선언
class PingPong {
}
- 상수 선언
- timeOutSeconds: Observable<Int>.timer에 들어갈 값이며, 5초안에 서버로부터 응답이 안오면 타임아웃할때 사용
- throttleSeconds: 앱에서 서버로 ping을 보낼때 연속적으로 보내지 않고 스로틀링을 위해 적절한 시간에 보내기 위해 사용
private enum Const {
static let timeOutSeconds = 5
static let throttleSeconds = timeOutSeconds - 1
}
- disposeBag 선언
- disposeBag: 해당 인스턴스가 사라질때 자동으로 서버에 ping을 요청했을때 응답을 처리하는 스트림 해제에 사용
- timeoutDisposeBag: timer를 계속 초기화시켜줄때 사용
private var disposeBag = DisposeBag()
private var timeoutDisposeBag = DisposeBag()
- 외부에서 호출하는 runPingPong 메소드 구현
func runPingPong(_ completion: @escaping () -> ()) {
self.sendPing { completion() } // 아래에서 구현 예정
}
- sendPing 구현
- 1) 핑을 보내는 부분
- 2) 타이아웃을 시작하는 부분 (핵심)
// 1)
private func sendPing(_ completion: @escaping () -> ()) {
API.requestPing()
.observe(on: ConcurrentDispatchQueueScheduler.init(qos: .background))
.throttle(.seconds(Const.throttleSeconds), scheduler: ConcurrentDispatchQueueScheduler.init(qos: .background))
.subscribe(with: self, onNext: { ss, _ in
ss.receivePong { completion() } // 아래에서 구현
})
.disposed(by: self.disposeBag)
// 2)
Observable<Int>
.timer(.seconds(Const.timeOutSeconds), scheduler: ConcurrentDispatchQueueScheduler.init(qos: .background))
.observe(on: ConcurrentDispatchQueueScheduler.init(qos: .background))
.subscribe(onNext: { _ in
completion()
})
.disposed(by: self.timeoutDisposeBag)
}
- receivePong 구현
- 응답을 받으면 타임아웃을 초기화
- 다시 sendPing 수행 (반복)
private func receivePong(_ completion: @escaping () -> ()) {
print("receive pong")
self.timeoutDisposeBag = DisposeBag()
self.sendPing { completion() }
}
* 전체 코드: https://github.com/JK0369/ExPingPong
'iOS 응용 (swift)' 카테고리의 다른 글
Comments