When SwiftUI was first announced I decided not to even look at it.
First of all, I didn't want to spoil the overall impression of undercooked software. Secondly, I didn't want to fall in love and then wait a year before being able to use it on daily basis.
Four months ago I decided that it was the perfect time to dive into SwiftUI entirely.
Debates around SwiftUI
SwiftUI layout is not so obvious as plain old autolayout constraints. At least for some time at the beginning.
Imagine that want some specific layout behavior, like expanding some text labels horizontally depending on text length until some max size proportional to the container then expanding vertically by pushing other views down.
Luckily that kind of thing can be done in SwiftUI with the help of googling the following things: spacers, layout priorities,
fixedSize modifiers along with
I say luckily because at first sight there were no signs of any possibility to make such kind of layouts.
In general, it seems that SwiftUI allows us to build almost any kind of layout and make it pixel perfect.
The declarative concept is great. I love how it makes the code so comprehensible and clean even for rather complicated layouts. It really simplifies the UI development.
On another hand, the magical elegance of SwiftUI API is the result of a lot of complexity under the hood. In some way, it brings such a ridiculous thing as UI development to a C++ templates level of things.
Generic types with constraints everywhere, opaque types, function builders. That may be too much for newcomers to iOS development and Swift.
UIKit compared to SwiftUI is like AK47 compared to a blaster from Cyberpunk 2077.
It's not bad news or something. It's just a fact that using SwiftUI involves using advanced coding techniques that other programming languages may not even have.
Lack of documentation and community.
A decade with UIKit has brought us a ton of tutorials, examples and answers on SO for all possible problems developers faced during that time. SwiftUI is not even closely comparable.
An incomplete collection of components
Sad but true that there are many things missing. Many things exist but lack some customization API.
Fortunately, we can bridge any component from UIKit easily. And it would be fully acceptable. Furthermore, many of SwiftUI components are just a wrap over UIKit/AppKit components.
That bridging has a certain drawback. If we are going to implement a multiplatform app and want to use some component that is not implemented in SwiftUI, we will have to implement equivalents and bridge them for every platform.
Actually, nobody knows for sure now how the whole thing will perform in case of a really huge app and bloated UI hierarchy.
I've already heard complaints on how it works with AppKit from Dimillian adding to it some research from Peter Steinberger here. That all sound a little bit disappointing. Hope that things will get better.
In my opinion, dealing with SwiftUI requires us to leave some room for optimizations on the architecture level of the app.
Taking into account SwiftUI's constant wish to re-render UI on every update we definitely need to leave a place to throttle and debounce updates and then perform manual EquatableView diffing based on view models.
So we simply should not rely the whole app on those ObservableObject guys entirely right in the View layer.
Adoption in existing apps
SwiftUI is very attractive not only because it's so elegant, but mainly because it allows us to build UI faster. That makes is so tempting to bring it to existing projects right now. Luckily we don't need to rewrite apps from scratch.
As you might probably know, there is a two-way bridging for UIKit and SwiftUI.
- SwiftUI view can be embedded as a view of HostViewController and treated as a plain old ViewController.
- UIView or UIViewController can be embedded into SwiftUI view by conforming to UIViewRepresentable and UIViewControllerRepresentable
That means that we have some options when deciding how to deal with SwiftUI in existing apps.
Since we decide to adopt SwiftUI we can either
- implement new screens in SwiftUI entirely, embedding existing UI components into it
- move carefully, implementing new small pieces of UI in SwiftUI and embedding them in the existing UIKit app.
It reminds me of the times when Swift itself has just appeared and developers started to make their first cautious steps in bringing Swift code into their Obj-C apps.
What I hate most in SwiftUI
While everyone is complaining about navigation in SwiftUI, I'd bravely say that it's just fine.
There is a pretty cool attempt to make it data-driven by programmatically binding it to the state. But unfortunately, that doesn't work as smoothly as expected.
When performing navigation between screens, under the hood SwiftUI uses a plain old UIKit navigation stack (at least on iOS) with an embedded SwiftUI View like this:
SwiftUI View -> HostingViewController -> NavigationController stack
It works nicely until your state says that you should immediately navigate N screens back or N screens forward.
In case of popping back to the root, it just looks a little bit buggy. In case of pushing several screens forward, it crashes because navigation is performed with animation and nobody waits for its completion.
UPD: Pushing several screens forward seems to be fixed. At least it doesn't crash anymore though still looks a little bit jumpy.
As for full-screen modal presentation missing. First of all, is already available in iOS14, secondly, it was possible to hack it by using NavigationController directly.
Stranger things about navigation
Another not-so-obvious thing is that SwiftUI doesn't inject environment objects into the view hierarchy when presenting the view as a sheet. It just presents it as a separate navigation stack, so requires manual injection. Weird but true. (Probably fixed already in iOS14)
Glitches and stitches
I love to polish UI until it reaches the state of smoothie.
Unfortunately, SwiftUI constantly brings new nasty surprises here and there that don't allow me to reach the complete smoothie state finally.
For example, in iOS14 there is an automatic keyboard avoidance. Depending on the layout of some screens its animation looks really ugly. So I have to use either manual implementation of keyboard avoidance or default.
Another example is unwanted animations of view because of layout diff misunderstandings.
It's quite annoying to spend some extra time inventing workarounds for those things.
Dirty Hacks 💩
What I don't like most is that sometimes due to the lack of many APIs we have to invent dirty workarounds, like introspecting lib or other things similar to those described in the article. I guess that it's a long time ahead to live with it, unfortunately.
Can we use SwiftUI in production now? 🤔
In my opinion... well... just start using it finally!
I think that gradually all the apps will migrate entirely during the next several years. So it's meaningless to deny SwiftUI until it reaches its perfect API shape or becomes absolutely stable. Now it's just the perfect time to obtain new skills in SwiftUI.
If the app's target version allows, the wisest would be to implement new features in SwiftUI fully or partially.
Great opportunity for brand new apps to go fully SwiftUI, taking into account its limitations.