티스토리 뷰
이 포스팅을 이해하려면 RxSwift vs Combine - 스펙 / 성능 / 개념 비교를 읽고 오세요 ☺️
Rxcocoa(for UIKit) + RxSwift 로 짰던 코드를
-> UIKit + Combine
-> SwiftUI + Combine
이렇게 두 가지 버전으로 바꿔보았습니다 :)
우선 Model/ViewModel 쪽 코드는 큰 차이가 없었습니다
APIManager 안에 있는 fetch 함수를 예로 봅시다 (isbn number를 받아서 책정보를 주는 함수입니다)
Observalbe을 AnyPulisher로 바꾸면 끝입니다
그 다음 APIMananger의 fetch 함수를 부르는 ViewModel 쪽 코드를 봅시다
여기도 subscribe를 sink로 바꿔주면 끝입니다
하지만 UIBinding 쪽 코드는 Rx를 빼고 Combine을 넣었을 때 그렇게 깔끔하지 않았습니다
두 가지 Case를 보면서 살펴봅시다
Case 1 : SearchBar의 Text를 한 글자씩 관찰하여 ViewModel의 search함수 호출한 후,
데이터를 받아 tableview reload 하기
[1] RxCocoa + RxSwift
먼저 처음에 Rx로 개발한 코드를 봅시다
(간단 버전이므로 tableview나 disposebag 같은 변수들이 빠져있는 것들이 있으니 참고해서 보아주세용 👏)
bindSearchBar함수를 봅시다
searchbar.rx.text로 searchbar의 text를 관찰해서 viewModel의 search함수를 호출해줍니다
bindTableview함수를 봅시다
viewmodel의 데이터 (publications)를 tableview에 바인딩 시켜줘서 데이터가 변하면 tableview가 reload 됩니다
viewModel은 이렇게 생겼습니다
[2] UIKit + Combine
이번엔 Rx를 빼고 combine을 넣어봅시다
(@Published 키워드가 붙은 것은 Publisher라고 생각하시면 됩니다)
searchbar와 searchText를 따로 선언해준 것을 볼 수 있구요, delegate 연결해서 searchText를 업데이트 시켜주는 코드가 들어가게 됩니다
viewModel 쪽도 Publisher로 바꿔준 것 말고는 거의 변한 것이 없습니다
[3] SwiftUI + Combine
이번엔 UIKit 대신 SwiftUI를 쓰는 것 까지 해봅시다
SwiftUI를 써보기 전 간단한 개념 조금만 알고 가봅시다
1) onReceive
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
/// Adds an action to perform when the given publisher emits an event.
///
/// - Parameters:
/// - publisher: The publisher to subscribe to.
/// - action: The action to perform when an event is emitted by
/// `publisher`.
/// - Returns: A view that triggers `action` when `publisher` emits an
/// event.
public func onReceive<P>(_ publisher: P, perform action: @escaping () -> Void) -> SubscriptionView<P, Self> where P : Publisher, P.Failure == Never
}
SwiftUI의 View들은 onReceive라는 것을 가지는데 onReceive의 Publisher에 넣어준 스트림의 이벤트가 발행될때마다 action이 실행됩니다 Rx의 view.rx 와 같다고 생각하면 됩니다
2) @State
@State를 붙이면 SwiftUI는 변화를 관찰하다가그 state를 사용하는 view의 body를 Automatically update시켜줍니다
@State property wrappers are being managed by a CurrentValueSubject from Combine. (사람들의 추측)
3) @ObjectBinding
@State: Used for when changes occur locally to your SwiftUI view
@ObjectBinding: Binds your SwiftUI view to an external data source
State와 같은 개념인데 viewModel과 같이 해당뷰 안에 있지 않은 외부의 소스를 관찰할 때 이 키워드를 써줍니다
그럼 이제 코드를 봐봅시다
searchText를 @State 키워드를 붙여주었고 viewModel에 @objectBinding을 붙여주었습니다
searchText를 TextField와 바인딩해주었고 (swiftUI에는 searchbar가 없어서 textfield로 해주었습니다)
textfield 에 한 글자 씩 들어올때마다 onReceive의 액션(viewModel의 search호출)이 실행됩니다
viewModel은 이렇게 생겼는데요
viewModel의 데이터가 업데이트될 때마다 didchange.send를 하게 되는데 이 viewModel를 가지고 있는 view의 body를 업데이트 시켜줘~ 하는 것 입니다
그래서 데이터(publications)가 바뀔 때 view의 List가 자동으로 업데이트 되게 됩니다
Case 2: 5개의 textfield를 관찰하여 모두 다 empty가 아닌 순간 Confirm Button 누를 수 있게 하기
[1] RxCocoa + RxSwift
기존에 Rx로 짰던 코드를 먼저 봅시다
textfield.rx.text 해서 만든 observable 다섯개를 연산해주는 코드가 나옵니다
[2] UIKit + Combine
그 다음 Rx를 빼고 Combine을 넣어봅시다
textfield와 textfield의 text가 empty인지 아닌지를 나타내는 불리언 값 선언을 따로 해줘야합니다 (저는 이 두 개가 분리되는게 별로라고 생각해요)
그리고 textfield가 바뀌는 것을 text에 넣어주는 코드가 들어가게 됩니다
[3] SwiftUI + Combine
SwiftUI로 까지 바꾸어봅시다
관찰할 텍스트를 textfield에 바인딩해주었습니다
isConfirmValid가 바뀔 때마다 버튼 enable여부가 바뀝니다
코드가 간단하고 깔끔하네요 :-)
느낀 점
-
Rx와 Combine은 거의 같습니다. 하지만 조금씩 다른 부분이 있어서 완전히 같다고 생각하고 쓰면 예상치 못한 문제를 만날 수 있을 것만 같아요....!
ex. BehaviorSubject와 CurrentValueSubject
ex. subscribeOn -
iOS 13이상이라면 RxSwift를 빼고 Combine을 쓸 수는 있습니다
하지만 RxSwfit를 Rxcocoa와 함께 쓰는 것 처럼 Combine은 SwiftUI와 함께 쓰는 것이 코드가 깔끔합니다 -
덧붙여서 Combine은 SwiftUI와 함께 써야 Apple이 Combine을 만든 의도를 살릴 수 있습니다 예를 들어 애플에서 viewModel을 BindableObject 프로토콜 따르게 만들라고 가이드를 해줬는데 (WWDC 영상에서) BindableObject는 SwifUI 소속이랍니다
'🍏 > SwiftUI + Combine' 카테고리의 다른 글
[SwiftUI] 뷰의 이니셜라이저에서 @State, @Binding, @EnvironmentObject에 접근하기 (1) | 2020.08.31 |
---|---|
[SwiftUI] Multi-platform App 만들기 - 프로젝트 세팅 (2) | 2020.08.06 |
[SwiftUI] ZStack 실전 예제들 (2) | 2020.05.16 |
[Combine] Cancellable과 AnyCancellable (6) | 2019.06.28 |
RxSwift vs Combine - 스펙 / 성능 / 개념 비교 (16) | 2019.06.28 |
- Total
- Today
- Yesterday
- ipad multitasking
- flutter 앱 출시
- Dart Factory
- Django Firebase Cloud Messaging
- Flutter Text Gradient
- github actions
- Python Type Hint
- drf custom error
- 장고 URL querystring
- Django Heroku Scheduler
- DRF APIException
- METAL
- Flutter Spacer
- Sketch 누끼
- 플러터 얼럿
- 플러터 싱글톤
- 장고 Custom Management Command
- SerializerMethodField
- PencilKit
- Watch App for iOS App vs Watch App
- flutter deep link
- ribs
- Flutter getter setter
- 구글 Geocoding API
- Flutter Clipboard
- Flutter 로딩
- Django FCM
- flutter dynamic link
- cocoapod
- flutter build mode
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |