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 by an undercooked software. Secondly, I didn't want to fall in love and then to wait a year before being able to use it on daily basis.
Four month ago I decided that it's 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 behaviour, like expand some text label horizontally depending on text length until some max size proportional to the container then expand vertically by pushing other views down.
Luckily that kind of things can be done in SwiftUI with the help of googling the following things: spacers, layout priorities, fixedSize modifiers along with geometry readers and alignment guides.
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 to build almost any kind of layout and make it pixel perfect.
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 that 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 in 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 close 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 optimisations 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 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 imbedded 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 existing UIKit app.
It reminds me the times, when Swift itself has just appeared and developers started to make first cautious steps bringing Swift code into their Obj-C apps.
What I hate most in SwiftUI
While everyone is complaining on navigation in SwiftUI, I'd bravely say that it's just fine.
There is a pretty cool attempt to make it data-driven by programatically binding it to the state. But unfortunately that doesn't work as smooth as expected.
When performing navigation between screens, under the hood SwiftUI uses plain old UIKit navigation stack (at least on iOS) with embedded SwiftUI View like this:
SwiftUI View -> HostingViewController -> NavigationController stack
It works nice until your state says that you should immediately navigate N screens back or N screens forward.
In case of popping back to 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 any more 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 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 doesn't allow me to reach the complete smoothie state finally.
For example, in iOS14 there is an automatic keyboard avoidance. Depending on 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 of APIs we have to invent dirty workarounds, like introspect lib or other things similar to described in the article. I guess that it's 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 it's perfect API shape or become absolutely stable. Now it's just perfect time to obtain new skills in SwiftUI.
If the app's target version allows, the most wise 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.