visit
How SwiftUI simplifies UI building
Today in the vast majority of cases UI building involves using an Interface Builder where you set UI components and their locations relative to each other. Then these components get using Outlets, Actions, etc. Thus, the user interface and its behavior are essentially created in two separate places, which in itself is not very convenient.An alternative to this is making UI in code. Though at the moment this is an even more difficult task. For example, here’s what button building looks like:How SwiftUI works
As mentioned above, SwiftUI uses . What exactly is Domain-specific language? It’s a so-called domain language that allows describing primitives of a certain particular domain on the basis of a high-level language (in our case it’s Swift). Then, with the help of these primitives, tasks specific to the subject area are solved. In essence, a new language is built on the basis of the old one.In the example above, such primitives are Button and Text.In order for SwiftUI syntax to be as simple and straightforward as possible, some changes were introduced in Swift 5.1.Here are some of those changes:
Function builders
Thanks to this addition, the syntax like this one became possible:HStack {
<span class="hljs-function" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none;"><span class="hljs-title" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(28, 0, 207);">Text</span><span class="hljs-params" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(92, 38, 153);">(<span class="hljs-string" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(196, 26, 22);">"SwiftUI"</span>)</span></span>
<span class="hljs-function" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none;"><span class="hljs-title" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(28, 0, 207);">Text</span><span class="hljs-params" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(92, 38, 153);">(<span class="hljs-string" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(196, 26, 22);">"rocks"</span>)</span></span>
}
Opaque return types
It allows you to return a protocol with associated type from a function and eliminates the need to explicitly specify generic parameters of the return type:<span class="hljs-keyword" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">var</span> body: some <span class="hljs-type" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(92, 38, 153);">View</span> <span class="hljs-meta" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(28, 0, 207);">{...}</span>
Property wrappers
SwiftUI uses this to bind the object’s properties to View.What is behind this description
When you begin to dig into Combine’s documentation and deal with such technical terms as Publisher, Subscriber, Operators, Cancellable, Scheduler, it immediately becomes clear that the Combine framework is basically an implementation of Apple’s functional reactive programming paradigm.iOS programmers familiar with such libraries as and , immediately get why Combine was created in the first place and what tasks it was supposed to solve. Besides, with Combine, there’s no more need to use any third-party solutions.What tasks Combine solves
FRP paradigm in general, and Combine in particular increases the level of code abstraction. It allows you to concentrate on events that determine the business logic of the application, instead of spending time on dealing with a large number of implementation details. All this allows reducing the amount of boilerplate code (DispatchQueues, Delegates, KVOs, Target-Actions and etc.).Benefits of using Combine framework:
We could use DispatchGroup and DispatchQueue to solve this complex task. It will require some boilerplate code to create a queue, group, add tasks to queue and subscribe to the callback. Things get a little more complicated if asynchronous tasks should return some kind of result. In this case, you’ll need to create instance variables and write and read values from there.
This is how the solution looks like in Combine:Publishers.Zip3(intAsyncTask, stringAsyncTask, voidAsyncTask)
<span class="hljs-selector-class" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(155, 112, 63);">.sink</span> { (intValue, stringValue, _) <span class="hljs-keyword" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">in</span>
<span class="hljs-comment" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(0, 106, 0);">// tasks executions are finished</span>
}
<span class="hljs-class" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none;"><span class="hljs-keyword" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">class</span> <span class="hljs-title" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(92, 38, 153);">ResetPasswordModel</span>: <span class="hljs-type" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(92, 38, 153);">ObservableObject {</span></span>
<span class="hljs-meta" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(28, 0, 207);">@Published</span> <span class="hljs-keyword" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">var</span> email = <span class="hljs-string" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(196, 26, 22);">""</span>
}
ResetPasswordModel conforms ObservableObject protocol, which means that the ResetPasswordModel’s fields can be used for SwiftUI’s bindings.The @Published modifier creates a publisher for the email field, so now it is possible to observe the email property.
Second, let’s define the UI with SwiftUI.struct ResetPasswordView: View {
@ObservedObject private <span class="hljs-selector-tag" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">var</span> model = ResetPasswordModel()
<span class="hljs-selector-tag" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">var</span> <span class="hljs-selector-tag" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(170, 13, 145);">body</span>: some View {
Form {
Section { TextField(<span class="hljs-string" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(196, 26, 22);">"Email"</span>, text: <span class="hljs-variable" style="-webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; box-sizing: border-box; outline: none; color: rgb(102, 102, 0);">$model</span>.email) }
}
}
Written by Ruslan Krohalev and Kate Shokurova. Previously published at //shakuro.com/blog/how-to-integrate-combine-with-swiftui-to-make-better-apps