The first thing you should know about SwiftUI is that it is not a new programming language, and neither is it an updated version of the Swift language that has a declarative syntax feature. This has caused some confusion, especially among newer Swift developers. So what is SwiftUI?
SwiftUI is Apple’s new UI Framework that was created to replace the well known UIKit Framework with its Storyboards, XIBs, Segues, and Autolayout, enabling developers to work in the UI layer in an easier and faster manner.
What makes SwiftUI’s declarative syntax possible is a combination of new features implemented in Swift 5.1 and older Swift features. Let's take a look at each of these:
Implicit Return Types
As of Swift 5.1, you can omit the return statement keyword in any function or computed property that has only one expression:
This is what makes it possible, for example, to declare a SwiftUI Text view inside the view body:
Instead of explicitly writing a return keyword:
It’s worth pointing out that, even though you don’t need to write the "return" keyword anymore, you still have the option of writing it, and your code will work the same way. So even though it can be omitted, the return statement is still available. (This new feature used in regular functions and computed properties already existed inside closures in previous versions of Swift.)
Opaque Return Types
Wondering what that strange some keyword is for in SwiftUI’s body declaration? That means the body computed property returns an Opaque Type, a new Swift 5.1 feature that allows functions and computed properties to return any value that conforms to a specific protocol. The concrete returned type is hidden, and it doesn’t matter which one will be used, as long as it conforms to the protocol.
In the example below, the first function returns an Int concrete type, while the second returns an Opaque Type (any type that conforms to the Equatable Protocol would fit):
In a SwiftUI view body, we can return any type that conforms to the View Protocol, which includes many different views from SwiftUI Framework, like Circle( ), for example, as well as your own custom views:
Method Chaining in View Modifiers
In SwiftUI, you use View Modifiers to change the properties of a view. View Modifiers are simply methods you append to a view one after another (e.g. .font(.title), .foregroundColor(.yellow), .frame(), and so on). Although this is a new SwiftUI feature, View Modifier uses a technique called Method Chaining that isn't new in the Swift language.
Many View Modifiers can be applied to all views, like .foregroundColor(.yellow), while others are specific to particular views, like .bold(), which belongs to Text views.
One important thing to notice is that the modifier’s order matters, so the same modifier in a different order can give you a completely different result. That’s because a View Modifier returns another view with the transformations applied, so the next modifier is always applied to the view returned by the previous one.
Trailing Closures and Function Builders in Container Views
If you try to put more than one view inside the body of a SwiftUI view, the compiler will complain. Remember that implicit return only works in functions or computed properties that have a single expression? But no screen is made of just one view. To solve this, SwiftUI has container views. The most common are the 3 types of stacks, HStack, VStack and ZStack, which manage the layout of other views horizontally, vertically, and layered on top of each other, respectively.
These views use a different SwiftUI syntax where the developer can declare views inside braces, one after another, in the body of the stack. This is possible due to the combination of Trailing Closures and a new Swift 5.1 feature called Function Builders.
If you take a look at the HStack init method in Apple’s documentation, you can see the last parameter is a function of type ( ) -> Content:
Since we can use a Trailing Closure when it’s the last parameter in a function (which means declaring the content in braces outside the parentheses and omitting the parameter name), it’s possible to declare our views directly inside the braces of the HStack init method:
But inside a Trailing Closure, it still wouldn’t be possible to put views one after another in a declarative way. If you notice in the HStack init method above, the last parameter that is a function of type ( ) -> Content has a @ViewBuilder annotation. This is a new Swift 5.1 feature called Function Builders, which is what makes this syntax possible. Function Builders are an advanced Swift topic, but in simple terms, they are specially annotated functions, used to implicitly build a value from a sequence of statements or expressions, producing a single value piece.
In SwiftUI, you will find some stored properties with annotations like @State, @Binding, etc. These use a new Swift 5.1 feature called Property Wrappers. A simple definition of a Property Wrapper is a generic Swift struct that encapsulates read and write access to a property while adding some extra behavior to augment its semantics.
Using a Property Wrapper, you can attach custom code to any stored property. So every time the value of the property changes, the connected code is executed. What a Property Wrapper does depends completely on the code you write for it.
According to Apple’s documentation on SwiftUI’s @State Property Wrapper:
“SwiftUI manages the storage of any property you declare as a state. When the state value changes, the view invalidates its appearance and recomputes the body. Use the state as the single source of truth for a given view. A State instance isn’t the value itself; it’s a means of reading and writing the value. To access a state’s underlying value, use its variable name, which returns the wrappedValue property value.”
As a practical example, let’s write a Property Wrapper that will assure a String is Lowercased any time a value is assigned to the property:
This way, no matter the String that’s passed into the init method of ProfileView, the email will always be displayed lowercased:
That covers the most important new Swift 5.1 features that make SwiftUI syntax possible. As a brand new and innovative way to build UIs across Apple platforms, SwiftUI is continually under development, and we can expect more exciting new features on this fantastic UI Framework later this year on Apple’s WWDC.
The source code examples in this article can be found here. Enjoy!
Based in São Paulo, Marcos Rebouças is an iOS Engineer at Avenue Code that’s passionate about transforming app prototypes into real amazing user experiences. When not coding he also enjoys to practise yoga and spend time with his family and friends.