Rxswift (1) Functional responsive programming idea
RxSwift (II) Sequence core logic analysis
Create, subscribe, and destroy an RxSwift Observable
RxSwift (4) higher-order functions
RxSwift (v)
(6) Dispose source code analysis
RxSwift (7) RxSwift vs. SWIFT usage
RxSwift (x) Basic Usage part 1- Sequence, subscribe, destroy
RxSwift Learning 12 (Basics 3- UI Control Extensions)
@TOC
Rxswift common data processing
Target Action
Example 1:
- Traditional code
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
func buttonTapped(a) {
print("button Tapped")}Copy the code
- Rxswift code
button.rx.tap
.subscribe(onNext: {
print("button Tapped")
})
.disposed(by: disposeBag)
Copy the code
You don’t need to use Target actions to make the code logic visible.
The agent
Example 2:
- Traditional code
class ViewController: UIViewController {...override func viewDidLoad(a) {
super.viewDidLoad()
scrollView.delegate = self}}extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("contentOffset: \(scrollView.contentOffset)")}}Copy the code
- Rxswift code
class ViewController: UIViewController {...override func viewDidLoad(a) {
super.viewDidLoad()
scrollView.rx.contentOffset
.subscribe(onNext: { contentOffset in
print("contentOffset: \(contentOffset)")
})
.disposed(by: disposeBag)
}
}
Copy the code
Rxswift implementation of the proxy, you do not need to write the proxy configuration code, you can get the desired results.
notice
Example 3:
- Traditional code
var ntfObserver: NSObjectProtocol!
override func viewDidLoad(a) {
super.viewDidLoad()
ntfObserver = NotificationCenter.default.addObserver(
forName: .UIApplicationWillEnterForeground,
object: nil, queue: nil) { (notification) in
print("Application Will Enter Foreground")}}deinit {
NotificationCenter.default.removeObserver(ntfObserver)
}
Copy the code
- Rxswift code
NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification)
.subscribe(onNext: { (noti) in
print(noti)
})
.disposed(by: disposeBag)
Copy the code
Back closure
Example 4:
- Traditional code
URLSession.shared.dataTask(with: URLRequest(url: url)) {
(data, response, error) in
guard error == nil else {
print("Data Task Error: \(error!)")
return
}
guard let data = data else {
print("Data Task Error: unknown")
return
}
print("Data Task Success with count: \(data.count)")
}.resume()
Copy the code
- Rxswift code
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(onNext: { data in
print("Data Task Success with count: \(data.count)")
}, onError: { error in
print("Data Task Error: \(error)")
})
.disposed(by: disposeBag)
Copy the code
KVO
Example 5:
- Traditional code
Copy the code
- Rxswift code
// Listen for changes in the name of the person object
self.person.rx.observeWeakly(String.self."name")
.subscribe(onNext: { (value) in
print(value as Any)
})
.disposed(by: disposeBag)
Copy the code
gestures
Example 6:
- Traditional code
Copy the code
- Rxswift code
let disposeBag = DisposeBag(a)let tap = UITapGestureRecognizer(a)self.label.addGestureRecognizer(tap)
self.label.isUserInteractionEnabled = true
tap.rx.event.subscribe(onNext: { (tap) in
print(tap.view)
})
.disposed(by: disposeBag)
Copy the code
The network request
Example 7:
- Traditional code
Copy the code
- Rxswift code
let url = URL(string: "https://www.baidu.com")
URLSession.shared.rx.response(request: URLRequest(url: url!) ).subscribe(onNext: { (response,data)in
print(response)
}, onError: { (error) in
print(error)
}, onCompleted: {
}).disposed(by: disposeBag)
Copy the code
The timer
Example 8:
- Traditional code
Copy the code
- Rxswift code
let disposeBag = DisposeBag(a)var timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
timer.subscribe(onNext: { (num) in
print(num)
})
.disposed(by: disposeBag)
Copy the code
There are dependencies between multiple tasks
Example 9: For example, the Token is obtained through the username and password and then the user information is obtained through the Token
- Traditional code
// encapsulate the interface with a callback
enum API {
// get a token by username and password
static func token(username: String, password: String,
success: (String) -> Void,
failure: (Error) - >Void) {... }// Obtain user information through token
static func userinfo(token: String,
success: (UserInfo) -> Void,
failure: (Error) - >Void) {... }}/// Obtain user information by user name and password
API.token(username: "beeth0ven", password: "987654321",
success: { token in
API.userInfo(token: token,
success: { userInfo in
print("Obtaining user information successfully:\(userInfo)")
},
failure: { error in
print("Failed to obtain user information:\(error)")
})
},
failure: { error in
print("Failed to obtain user information:\(error)")})Copy the code
- Rxswift code
// encapsulate the interface with Rx
enum API {
// get a token by username and password
static func token(username: String, password: String) -> Observable<String> {... }// Obtain user information through token
static func userInfo(token: String) -> Observable<UserInfo> {... }}/// Obtain user information by user name and password
API.token(username: "beeth0ven", password: "987654321")
.flatMapLatest(API.userInfo)
.subscribe(onNext: { userInfo in
print("Obtaining user information successfully:\(userInfo)")
}, onError: { error in
print("Failed to obtain user information:\(error)")
})
.disposed(by: disposeBag)
Copy the code
Wait for multiple concurrent tasks to complete
Example 10: For example, two network requests need to be merged into one
With Rx:
// encapsulate the interface with Rx
enum API {
/// get the teacher's details
static func teacher(teacherId: Int) -> Observable<Teacher> {... }/// get the teacher's comment
static func teacherComments(teacherId: Int) -> Observable"[Comment] > {... }}/// get both teacher information and teacher comments
Observable.zip(
API.teacher(teacherId: teacherId),
API.teacherComments(teacherId: teacherId)
).subscribe(onNext: { (teacher, comments) in
print("Success in obtaining teacher information:\(teacher)")
print("Success in obtaining teacher comments:\(comments.count)Article")
}, onError: { error in
print("Failure to obtain teacher information or comment:\(error)")
})
.disposed(by: disposeBag)
Copy the code
This allows you to perform fairly complex asynchronous operations in a few lines of code.
Data binding
Example 11:
Let’s compare these two pieces of code:
- Traditional code:
Set a single image to the imageView
let image: UIImage = UIImage(named: ...)
imageView.image = image
Copy the code
- Rx code:
let image: Observable<UIImage> =... image.bind(to: imageView.rx.image)Copy the code
Rx code: This code “syncs” an image sequence to imageView. Images in this sequence can be generated asynchronously. The image defined here is the blue part of the image above (the listening sequence) and imageView.rx.image is the orange part of the image above (the observer). This “synchronization mechanism” is data binding (subscription).
Rxswift UI usage
UILabel
Examples of 30:
- Traditional code
Copy the code
- Rxswift code
- Rxswift simply uses UILabel
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create a text label
let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
self.view.addSubview(label)
// Create a timer (send an index every 0.1 seconds)
let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
// Formats the elapsed time into the desired string and binds it to the label
timer.map{ String(format: "% % 0.2 d: % d. 0.2 0.1 d",
arguments: [($0 / 600) % 600, ($0 % 600 ) / 10, $0 % 10]) }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
Copy the code
- UILabel Rich Text: Binds data to the attributedText attribute
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create a text label
let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
self.view.addSubview(label)
// Create a timer (send an index every 0.1 seconds)
let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
// Formats the elapsed time into the desired string and binds it to the label
timer.map(formatTimeInterval)
.bind(to: label.rx.attributedText)
.disposed(by: disposeBag)
}
// Convert numbers into corresponding rich text
func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
let string = String(format: "% % 0.2 d: % d. 0.2 0.1 d",
arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
// Rich text Settings
let attributeString = NSMutableAttributedString(string: string)
// Start from text 0 with 6 character font helveticaneue-bold, size 16
attributeString.addAttribute(NSAttributedStringKey.font,
value: UIFont(name: "HelveticaNeue-Bold", size: 16)! , range:NSMakeRange(0.5))
// Set the font color
attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
value: UIColor.white, range: NSMakeRange(0.5))
// Set the text background color
attributeString.addAttribute(NSAttributedStringKey.backgroundColor,
value: UIColor.orange, range: NSMakeRange(0.5))
return attributeString
}
}
Copy the code
UIButton
Examples of 40:
- Traditional code
self.button.addTarget(self, action:#selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
@objc func buttonTapped(sender:UIButton?){}Copy the code
- Rxswift code
let disposeBag = DisposeBag(a)RX default tap is the tap event, since tap events are used most frequently
self.button.rx.tap
.subscribe(onNext: { () in
print("Click here.")
})
.disposed(by: disposeBag)
//RXSwift listens for events other than button clicks:
self.button.rx.controlEvent(.touchUpOutside).subscribe(onNext: { () in
})
.disposed(by: disposeBag)
Copy the code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)@IBOutlet weak var button: UIButton!
override func viewDidLoad(a) {
// Button click response 1
button.rx.tap
.subscribe(onNext: { [weak self] in
self? .showMessage("Button clicked")
})
.disposed(by: disposeBag)
// Button click response 2
button.rx.tap
.bind { [weak self] in
self? .showMessage("Button clicked")
}
.disposed(by: disposeBag)
//
}
// The binding of the button title
func test1(a) {
// Create a timer (send an index every 1 second)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
// Concatenate the latest title according to the index number and bind it to the button
timer.map{"Count\ [$0)"}
.bind(to: button.rx.title(for: .normal))
.disposed(by: disposeBag)
}
// The binding of the button's attributedTitle
func test2(a) {
// Create a timer (send an index every 1 second)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
// Format the past time into the desired string and bind it to the button
timer.map(formatTimeInterval)
.bind(to: button.rx.attributedTitle())
.disposed(by: disposeBag)
}
// Bind button icon (image)
func test3(a) {
// Create a timer (send an index every 1 second)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
// Select the corresponding button icon according to the index number and bind it to the button
timer.map({
let name = $0%2= =0 ? "back" : "forward"
return UIImage(named: name)!
})
.bind(to: button.rx.image())
.disposed(by: disposeBag)
}
// bind button backgroundImage
func test4(a) {
// Create a timer (send an index every 1 second)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
// Select the corresponding button background image based on the index number and bind it to the button
timer.map{ UIImage(named: "\ [$0%2)")! }
.bind(to: button.rx.backgroundImage())
.disposed(by: disposeBag)
}
// Convert numbers into corresponding rich text
func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
let string = String(format: "% % 0.2 d: % d. 0.2 0.1 d",
arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
// Rich text Settings
let attributeString = NSMutableAttributedString(string: string)
// Start from text 0 with 6 character font helveticaneue-bold, size 16
attributeString.addAttribute(NSAttributedStringKey.font,
value: UIFont(name: "HelveticaNeue-Bold", size: 16)! , range:NSMakeRange(0.5))
// Set the font color
attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
value: UIColor.white, range: NSMakeRange(0.5))
// Set the text background color
attributeString.addAttribute(NSAttributedStringKey.backgroundColor,
value: UIColor.orange, range: NSMakeRange(0.5))
return attributeString
}
// Displays a message prompt box
func showMessage(_ text: String) {
let alertController = UIAlertController(title: text, message: nil, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Sure", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)}}Copy the code
UIBarButtonItem
Example: 50
- Traditional code
Copy the code
- Rxswift code
Copy the code
UISwitch
Example: 60
- Traditional code
Copy the code
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
// segment select control
@IBOutlet weak var segmented: UISegmentedControl!
// Image display control
@IBOutlet weak var imageView: UIImageView!
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create an observable sequence of images that you currently want to display
let showImageObservable: Observable<UIImage> =
segmented.rx.selectedSegmentIndex.asObservable().map {
let images = ["js.png"."php.png"."react.png"]
return UIImage(named: images[$0])!
}
// Bind the image to the imageView
showImageObservable.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
func test1(a) {
switch1.rx.isOn.asObservable()
.subscribe(onNext: {
print("Current switching status:\ [$0)")
})
.disposed(by: disposeBag)
}
func test2(a) {
switch1.rx.isOn
.bind(to: button1.rx.isEnabled)
.disposed(by: disposeBag)
}
}
Copy the code
UISegmentedControl
Instance, 70:
- Traditional code
Copy the code
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
// segment select control
@IBOutlet weak var segmented: UISegmentedControl!
// Image display control
@IBOutlet weak var imageView: UIImageView!
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create an observable sequence of images that you currently want to display
let showImageObservable: Observable<UIImage> =
segmented.rx.selectedSegmentIndex.asObservable().map {
let images = ["js.png"."php.png"."react.png"]
return UIImage(named: images[$0])!
}
// Bind the image to the imageView
showImageObservable.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
func test1(a) {
segmented.rx.selectedSegmentIndex.asObservable()
.subscribe(onNext: {
print("Current item:\ [$0)")
})
.disposed(by: disposeBag)
}
}
Copy the code
UIActivityIndicatorView
Instance, 80:
- Traditional code
Copy the code
- Rxswift code
Copy the code
UITextField
Example 90: Basic usage of UITextField using Rxswift
- Traditional code
Copy the code
- Rxswift code
self.textFiled.rx.text.orEmpty
.subscribe(onNext: { (text) in
print(text)
})
.disposed(by: disposeBag)
// TextFiled Bind Button text
self.textFiled.rx.text
.bind(to: self.button.rx.title())
.disposed(by: disposeBag)
Copy the code
Example 91: Rxswift listens for changes in the contents of a single textField
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create a text input box
let textField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
textField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(textField)
// When the content of the text box changes, output the content to the console
textField.rx.text.orEmpty.asObservable()
.subscribe(onNext: {
print("What you typed is:\ [$0)")
})
.disposed(by: disposeBag)
// When the content of the text box changes, output the content to the console
textField.rx.text.orEmpty.changed
.subscribe(onNext: {
print("What you typed is:\ [$0)")
})
.disposed(by: disposeBag)
}
}
Copy the code
Example 92: Rxswift binds the contents of textField to other controls
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
// Create a text input box
let inputField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
inputField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(inputField)
// Create a text output box
let outputField = UITextField(frame: CGRect(x:10, y:150, width:200, height:30))
outputField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(outputField)
// Create a text label
let label = UILabel(frame:CGRect(x:20, y:190, width:300, height:30))
self.view.addSubview(label)
// Create button
let button:UIButton = UIButton(type:.system)
button.frame = CGRect(x:20, y:230, width:40, height:30)
button.setTitle("Submit".for:.normal)
self.view.addSubview(button)
// When the text box content changes
let input = inputField.rx.text.orEmpty.asDriver() // Convert a normal sequence to a Driver
.throttle(0.3) // If the value changes several times within 0.3 seconds, take the last time
// The content is bound to another input box
input.drive(outputField.rx.text)
.disposed(by: disposeBag)
// The content is bound to the text tag
input.map{ "Current word count:\ [$0.count)" }
.drive(label.rx.text)
.disposed(by: disposeBag)
// Buttons are available based on the number of words
input.map{$0.count > 5 }
.drive(button.rx.isEnabled)
.disposed(by: disposeBag)
}
}
Copy the code
Example 93: Rxswift listens for changes in the contents of multiple TextFields simultaneously
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)@IBOutlet weak var textField1: UITextField!
@IBOutlet weak var textField2: UITextField!
@IBOutlet weak var label: UILabel!
override func viewDidLoad(a) {
Observable.combineLatest(textField1.rx.text.orEmpty, textField2.rx.text.orEmpty) {
textValue1, textValue2 -> String in
return "The number you typed in was:\(textValue1)-\(textValue2)"}.map{$0 }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
Copy the code
TextField event listener Rx. ControlEvent Can listen for various events in the input box, and multiple event states can be freely combined. In addition to the touch events common to all UI controls, the input box has the following unique events:
-
EditingDidBegin: Start editing (start typing content)
-
EditingChanged: The input has changed
-
EditingDidEnd: End editing
-
EditingDidEndOnExit: Press the Return key to end editing
-
AllEditingEvents: Contains all previous edit-related events
-
Rxswift code
textField.rx.controlEvent([.editingDidBegin]) // States can be combined
.asObservable()
.subscribe(onNext: { _ in
print("Start editing!")
}).disposed(by: disposeBag)
Copy the code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
// User name input box
@IBOutlet weak var username: UITextField!
// Password input box
@IBOutlet weak var password: UITextField!
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
super.viewDidLoad()
// Press the Return key in the username input field
username.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: {
[weak self] (_) in
self? .password.becomeFirstResponder() }).disposed(by: disposeBag)// Press the return key in the password input box
password.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: {
[weak self] (_) in
self? .password.resignFirstResponder() }).disposed(by: disposeBag) } }Copy the code
Example 95: Rxswift implements textField event listening
- Rxswift code
Copy the code
UITextView
Instance, 100:
- Traditional code
Copy the code
- Rxswift code
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag(a)@IBOutlet weak var textView: UITextView!
override func viewDidLoad(a) {
// Start editing the response
textView.rx.didBeginEditing
.subscribe(onNext: {
print("Start editing")
})
.disposed(by: disposeBag)
// Finish editing the response
textView.rx.didEndEditing
.subscribe(onNext: {
print("End of edit")
})
.disposed(by: disposeBag)
// The content changes in response
textView.rx.didChange
.subscribe(onNext: {
print("The content has changed")
})
.disposed(by: disposeBag)
// Select part of the change response
textView.rx.didChangeSelection
.subscribe(onNext: {
print("The selected part changes.")
})
.disposed(by: disposeBag)
}
}
Copy the code
UITableView
- Traditional Swift uses UITableView instance 110:
// Song structure
struct Music {
let name: String / / title
let singer: String / / singer
init(name: String, singer: String) {
self.name = name
self.singer = singer
}
}
// Song list data source
struct MusicListViewModel {
let data = [
Music(name: "Unconditional", singer: Eason Chan),
Music(name: "You were a teenager.", singer: "S.H.E"),
Music(name: "The old me.", singer: "Kit Chan"),
Music(name: "In Jupiter", singer: "Hackberry")]}class ViewController: UIViewController {
/ / tableView object
@IBOutlet weak var tableView: UITableView!
// Song list data source
let musicListViewModel = MusicListViewModel(a)override func viewDidLoad(a) {
super.viewDidLoad()
// Set the proxy
tableView.dataSource = self
tableView.delegate = self}}extension ViewController: UITableViewDataSource {
// Returns the number of cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return musicListViewModel.data.count
}
// Returns the corresponding cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell")!
letmusic = musicListViewModel.data[indexPath.row] cell.textLabel? .text = music.name cell.detailTextLabel?.text = music.singerreturn cell
}
}
extension ViewController: UITableViewDelegate {
// Cell click
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Information about the song you selected [\(musicListViewModel.data[indexPath.row])】")}}Copy the code
- The UITableView Rxswift
Instance, 111:
/* We turn the data property into an Observable Squence, and the contents of the object are exactly the same as they were in the array. * /
// Song list data source
struct MusicListViewModel {
let data = Observable.just([
Music(name: "Unconditional", singer: Eason Chan),
Music(name: "You were a teenager.", singer: "S.H.E"),
Music(name: "The old me.", singer: "Kit Chan"),
Music(name: "In Jupiter", singer: "Hackberry"),])}import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
/ / tableView object
@IBOutlet weak var tableView: UITableView!
// Song list data source
let musicListViewModel = MusicListViewModel(a)// Responsible for object destruction
let disposeBag = DisposeBag(a)override func viewDidLoad(a) {
super.viewDidLoad()
// Bind data source data to tableView
musicListViewModel.data
.bind(to:
/* rx.items(cellIdentifier:) : This is a wrapper around rX based on the cellForRowAt data source method. In the traditional way we also have a numberOfRowsInSection method, which is no longer needed when we use Rx (Rx already does that for us). * /
tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell incell.textLabel? .text = music.name cell.detailTextLabel?.text = music.singer }.disposed(by: disposeBag)//tableView click response
/* rx.modelSelected: This is a wrapper around RX based on the UITableView delegate callback method didSelectRowAt. * / tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
print("Information about the song you selected [\(music)】")
}).disposed(by: disposeBag)
/*DisposeBag: Rx automatically interprets the resources bound to the view controller or its owner when it is about to be destroyed. It is implemented through a "subscription disposition mechanism" (similar to removeObserver of NotificationCenter). * /}}Copy the code
UICollectionView
Instance, 120:
- Traditional code
Copy the code
- Rxswift code
Copy the code
UIPickerView
Instance, 130:
- Traditional code
Copy the code
- Rxswift code
Copy the code
UIDatePicker
Instance, 140:
- Traditional code
Copy the code
- Rxswift code
Copy the code
UISlider
Instance, 150:
- Traditional code
Copy the code
- Rxswift code
Copy the code
UIStepper
Instance, 160:
- Traditional code
Copy the code
- Rxswift code
Copy the code