Arguably one of the biggest improvements in iOS programming in the past few years was the unveiling of SwiftUI at WWDC 2019.SwiftUI introduced new features, like the design canvas and “dynamic replacement”. It also enforces a strong declarative syntax to writing native iOS code, which takes away the burden of handling many different lifecycle methods/conformances and allows you to state exactly what the UI is.Consider the following Swift code:import UIKit
struct Post: Hashable, Identifiable {
var id: Int
var label: String
var author: String
}
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var posts: [Post] = [
Post(id: 0, label: "Post 1 Text", author: "John Doe"),
Post(id: 1, label: "Post 2 Text", author: "Einstein")
]
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
}
extension ViewController {
func setupTableView() {
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(UITableViewCell.self,
forCellReuseIdentifier: "PostTableViewCell")
}
}
extension ViewController: UITableViewDelegate {
// necessary conformance
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "PostTableViewCell")
if indexPath.row < posts.count {
let post = posts[indexPath.row]
cell?.textLabel?.text = post.label
}
return cell!
}
}
In this snippet we are displaying an list of posts in a basic UITableView component.We can do the same thing using SwiftUI:import SwiftUI
struct Post: Hashable, Identifiable {
var id: Int
var label: String
var author: String
}
struct ContentView: View {
var posts: [Post] = [
Post(id: 0, label: "Post 1 Text", author: "John Doe"),
Post(id: 1, label: "Post 2 Text", author: "Einstein")
]
var body: some View {
List(posts, id: \.self) { post in
HStack {
Text(post.label)
Text(post.author)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
As you can see, we’ve stripped out all of our lifecycle methods and replaced our class with a “struct”. What this means is that we have a Structure that conforms to the “View” protocol. Notice above that we’ve also removed our “import UIKit” reference, and this is because the “View” protocol is not in UIKit. It’s in a new package entirely: “SwiftUI”, which isn’t built on UIKit so you can’t directly use UIKit components like UITableView (you’d have to build a wrapper for it and make it conform to the UIViewRepresentable protocol if you did).
SwiftUI then takes this struct and finds the required "body" computed property and displays all of its content in the design canvas. This is where I’ve seen the biggest gains in my iOS app development. Because now I can add primitive views, such as Text or List, which will display on my canvas as I’m writing the code, and I won't have to worry about any delegate/datasource references or any issues with conforming with other protocols.
Not only that, say we wanted to change our list of posts inside the tableview to include the author of the post next to the label, then we can easily drag and drop a Text view into the canvas like so:And last but not least, we can actually run the app inside of the design canvas so we can watch the previewed content update in real time, while running the app! (If you’ve ever used cross platform frameworks to build apps then this is similar to hot reloading)
One of the most time and resource consuming processes is building and rebuilding projects (which has actually been reduced with the new Apple M1 chips) but we don’t need to worry about that now! The Swift compiler can “swap” edited code using a new feature called “dynamic replacement”. Which means we don’t have to re-compile the entire codebase in order to see our app live if we just changed the color of a button or text in a view.
In Conclusion:
SwiftUI let’s us state exactly what we want the UI to look like and how we want our users to interact with it. This is the power of declarative syntax, because with less responsibility to adhere to specific lifecycle methods and protocols, we can spend more time writing code that states exactly what we want the UI to look like. And we can quickly edit these properties through the new design canvas and watch our app come alive sooner rather than 200 build steps later.
In fact, this is a more Reactive approach to programming, and Apple gets that this is where the industry is heading. If you want to see more examples of this type of programming check out React or React Native for building mobile and web apps.