Now that iOS14 has been released, Swft itself has been updated and Swift UI has been standardized, I think there are many people who can't cut iOS12 and can't use Combine in practice.
But I want to try new technology. SwiftUI + Combine is a bit high hurdle, but first of all, I would like to try Combine alone with the familiar UIKit! !!
So, this time I wrote an article with the following contents.
I hope you find it useful. : bow:
This article has been confirmed to work in the following operating environment.
In a nutshell, it's Apple's genuine asynchronous framework`. I will quote the description of Apple Developer.
The Combine framework provides a declarative Swift API for processing values over time.
It means something like "The Combine framework provides a declarative API for processing values over time."
This is the main function of Combine, and it seems to be the nature of the asynchronous framework.
Before trying to use Combine, I will introduce the overall flow and the characters that you need to know to use Combine.
It looks like this in the figure.
In Rx and reactive programming, the above concept is often expressed by a marble diagram, Personally, it's easier to get the concept in the figure that shows the characters 1-1-1 as shown in the above figure.
Now that you know the characters, let's touch them for the time being.
This is the login screen you often see. If you're designing with an MVVM, you need to bind the email address you receive from the TextField in your View to your ViewModel. Let's take the implementation at that time as an example to see the explanation and implementation example of Publisher, Operator, and Subscriber.
Publisher First is Publisher. https://developer.apple.com/documentation/combine/publisher
Publisher is a great guy who can publish values, so you can publish the email address you received in View.
First, let's create a Publisher that publishes a value when the text of the TextField changes.
import Combine
final class LoginViewController: UIViewController {
@IBOutlet weak var mailAddressTextField: UITextField!
private let viewModel = LoginViewModel()
private var binding = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
//When textDidChangeNotification is notified`mailAddressTextField`Issue the object.
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: mailAddressTextField)
}
}
Don't forget to import.
Now when the textField changes, an object called mailAddressTextField
will be issued.
Operator Next, let's go to Operator. The Operator is a great guy who can convert values, so you can also convert the UITextField object published by Publisher above. When binding to a ViewModel with a TextField value, just a String is enough to pass to the ViewModel. So let's use Operator to convert the UITextField to a String.
import Combine
final class LoginViewController: UIViewController {
@IBOutlet weak var mailAddressTextField: UITextField!
private let viewModel = LoginViewModel()
private var binding = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: mailAddressTextField)
.compactMap { $0.object as? UITextField } //If you fail to cast UITextField and it becomes nil, play it
.map { $0.text ?? "" } //Extract text from UITextField and convert to String
}
}
.compactMap
..map
and convert it to String.I am doing that.
In this way, when the value issued by Publisher and the value you want to receive are different, the Operator handles the conversion and handling of the value in the middle. See below for Operator types.
Subscriber The last is Sbscriber. Since Sbscriber is a great guy who can receive values and do various things, you can set the String of the email address sent from Publisher to the ViewModel.
import Combine
final class LoginViewController: UIViewController {
@IBOutlet weak var mailAddressTextField: UITextField!
private let viewModel = LoginViewModel()
private var binding = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: mailAddressTextField)
.compactMap { $0.object as? UITextField }
.map { $0.text ?? "" }
.removeDuplicates() //Eliminate duplicate values
.eraseToAnyPublisher()
.receive(on: RunLoop.main)
.assign(to: \.mailAddress, on: viewModel) //viewModel\.Assign a value to mailAddress
.store(in: &binding)
}
}
final class LoginViewModel {
var mailAddress: String = "" {
didSet {
print(mailAddress)
}
}
}
It looks like you're doing a lot, but there are two points.
.assign (to: \ .mailAddress, on: viewModel)
is set in ViewModel..store (in: & binding)
.The assign method grows from Publisher and can generate a Subscriber while passing the received value to the object defined by keypath.
However, if it is left as it is, the memory will not be released, so we are calling .store (in: & binding)
to cancel the monitoring.
With the code so far, when you receive the value of TextField, it will be set in ViewModel!
Combine is Apple's genuine asynchronous framework and has the following features.
Combine has the following major characters:
In order to get used to Combine, I am also making an application that manages books by hitting API with UIKit and Combine. I'm planning to include an API client that incorporates Combine and Publisher that has been made into an extension to make it easier to use, so please have a look if you like: bow:
kawano108/CombineBookManagerApp
Recommended Posts