A full host of new features were announced at WWDC 2019, but there have been two features that have been getting more of a buzz than any others. Not since the announcement of Swift back in 2014, has Apple released something which could potentially change the way we develop apps in such a significant way.
Swift UI is a decorative framework which is powered by Apple’s new reactive component called Combine. It allows developers to rapidly write their UI, with very few lines of code. Combine, then allows for objects to react to state changes through publishers and object bindings, very similar to how reactive frameworks work.
Below is an example of a simple table view which updates based on the state property changes.
struct PostsView: View {
// Listens out for any changes to this property. If anything does change the body will be updated.
@ObjectBinding var state: PostsPresenter
var body: some View {
VStack {
List {
// Loops through the posts and create a custom PostRow for each one.
ForEach(state.posts) { post in
PostRow(title: post.title, url: post.url)
}
}
// Simple button at the bottom to refresh the model
Button(action: { self.state.refresh() }) {
Text("Refresh")
}
// Think of this like viewWillAppear. Everytime the view appears it will tell the presenter that it has arrived, so it can update the data.
}.onAppear {
self.state.arrived()
}
}
}
For the PostRow, it is a very similar process. We create a struct conforming to View, and provide it a body.
struct PostRowImage: View {
// This is what loads the remote images. We won't worry too much about the implementation of this just yet.
@State var imageLoader: ImageLoader
var body: some View {
ZStack {
// When the image is downloaded the imageLoader state will change which automatically re-renders the view.
if self.imageLoader.image != nil {
// Create a SwiftUI Image and contructs the the layout and design using the new functional properties.
Image(uiImage: self.imageLoader.image!)
.resizable()
.aspectRatio(CGSize(width: 32, height: 5), contentMode: .fit)
.frame(height: 100)
.animation(.spring())
.shadow(radius: 8)
} else {
// For the placeholder
Rectangle()
.foregroundColor(.clear)
.frame(height: 100)
}
}
.onAppear {
self.imageLoader.loadImage()
}
}
}
Very similar to the table view, however, more styling has been applied to the image view. When styling a SwiftUI view, most of the functions will return the same view, just with the style applied. This is functional programming, and it is what allows the view to easily be constructed with the dot syntax above.
Finally, to display this view on the screen, it needs to be embedded inside a UIHostingController. Once that controller is presented, we end up with the screen below.
let view = PostsView()
let controller = UIHostingController(rootView: view)
UIHostingController is just a subclass of UIViewController, however, it has to be instantiated with a SwiftUI View. Once the HostingController is presented, any further configuration and navigation are all done through SwiftUI. My main concern is how we go about architecting SwiftUI workflows?
Apple has generally pushed an MVC architecture, but with that not really being a favourite in the development community, developers have moved to other avenues such MVVM, MVP or Viper. But how will SwiftUI fit in with those? With SwitUI being built on a reactive core, we may see a greater adoption of architecture strategies such as Flux and Redux, which are commonly used in reactive projects.