From UIKit to SwiftUI


SwiftUI
Jakub Fišer portrait
Jakub Fišer
iOS Developer
10 Dec 2021
36
Technology topics
#Programming

Many SwiftUI tutorials exist on the internet these days. This is not going to be one of them! Instead, today I’d like to share with you my personal story of how someone with 5-year prior development experience in UIKit (an older UI framework for iOS) learned an entirely different concept for the first time – SwiftUI (a new UI framework for all Apple platforms).

Many hands make light work

I joined CN Group this year and was assigned to a project written in SwiftUI. It was both exciting and a little scary at the same time, as SwiftUI introduced an entirely different paradigm to iOS and all my prior UIKit knowledge was of no help. Thankfully, my new and more experienced colleagues were at hand since CN Group is an early adopter of SwiftUI.

Since its introduction in June 2019, they have developed several applications of various types in SwiftUI. For example, CN Group released an application for e-commerce, requiring pixel-perfect design and tons of animation. Then there is an IoT (Internet of Things) application building upon BLE (Bluetooth Low Energy) communication with an external smart device. And last but not least there is an AR (Augmented Reality) application for construction workers that leverages a LiDAR scanner.

Lessons learned

Since SwiftUI is entirely different from UIKit, I had to start from the very beginning. A SwiftUI Views Quick Start guide [1] was recommended to me as a great starting point - and indeed, it was. I discovered lots of useful information about basic UI controls, layout components, view sizing, view modifiers and much more. Another help was All SwiftUI property wrappers explained and compared [2] that is very handy as a great overview. Here’s an example of how to use the @EnvironmentObject property wrapper to pass values down the view hierarchy.

// Pass values down
let contentView = ParentView()
            .environmentObject(theme)
            .environmentObject(PartialSheetManager())
            .environmentObject(DialogManager())

// Get values in any view down in hierarchy
struct AnyChildView: View {
    @EnvironmentObject var theme: Theme
    @EnvironmentObject var partialSheet: PartialSheetManager

    …
}

When I then started to code with SwiftUI on my own, it seemed to be quite easy. With less code required, UI development was super-fast and very intuitive. There is also a live preview feature that, most of the time, eliminates the need to run the application in a simulator. As a result, implementation time is significantly reduced, and it feels almost like magic! For example, a shape in the following figure can be implemented with just 20 lines of code! Plus, it scales, and you can set any background or border you want.

struct ProgressBarWithEndBubble: Shape {
    let scaleCircle: CGFloat = 0.5
    let scalePath: CGFloat = 12/32
    let startAngleCircle: Double = 202
    let endAngleCircle: Double = 158
    let startAnglePath: Double = 90
    let endAnglePath: Double = 270

    func path(in rect: CGRect) -> Path {
        let circleRadius = rect.height * scaleCircle
        let pathRadius = circleRadius * scalePath
        return Path { path in
            path.move(to: .init(x: pathRadius, y: rect.midY - pathRadius))
            path.addArc(center: .init(x: rect.maxX - circleRadius, y: rect.midY),
                        radius: circleRadius,
                        startAngle: .init(degrees: startAngleCircle),
                        endAngle: .init(degrees: endAngleCircle),
                        clockwise: false)
            path.addArc(center: .init(x: rect.minX + pathRadius, y: rect.midY),
                        radius: pathRadius,
                        startAngle: .init(degrees: startAnglePath),
                        endAngle: .init(degrees: endAnglePath),
                        clockwise: false)
        }
    }
}
Preview

Coming from an UIKit background, the most difficult part for me was getting used to the fact that I was no longer in control of the view hierarchy. As SwiftUI is a declarative framework, its main concept is that you define “what” should be displayed instead of “how” it should be implemented. As explained in Demystify SwiftUI [3], you still need to follow some rules in order to achieve the animations you desire. Your code is then transformed (and optimised) to the view hierarchy on your behalf. There is a downside - you will no longer get much benefit from the view hierarchy debugger.

I also struggled a bit with atomic design principles. Even though these are not directly involved in the SwiftUI framework, it helps to keep your code clean. Atomic design is a methodology that defines 5 levels of UI - atom, molecule, organism, template, screen - where each builds on lower-level components (e.g., molecules consist of atoms, etc.). In UIKit, every new UIView (the base class for viewable content) in a hierarchy could result in potential performance issue. This doesn’t apply for SwiftUI. On the contrary, you are encouraged to decompose your UI into smaller components with zero to little performance impact. This also results in improved code readability. Here is an example of such a component (two horizontally aligned buttons), that is both easy to reuse and to read:

struct AppLandingActionView: View {
    let onLogIn: Callback
    let onSignUp: Callback

    var body: some View {
        HStack(spacing: Theme.spaces.s4) {
            RoundedButton(“Log In”, .quaternary, action: onLogIn)
            RoundedButton(“Sign Up”, .primary, action: onSignUp)
        }
    }
}

Let’s be a little negative

To be honest, there is still some functionality missing from SwiftUI. This is particularly obvious if you know that something missing was available in UIKit. For example, in SwiftUI, List (equivalent to UITableView) is still quite limited, as there is no way to react to scroll events and, until recently, it was not even possible to customise separators (introduced with iOS 15 in September 2021). You also need to be cautious when it comes to GeometryReader as extensive use might result in performance issues. And even as basic a component as text inputs can give you hard times in some cases - there’s more about that in SwiftUI in production [4]. Luckily, SwiftUI and UIKit are interoperable with each other, so if you find something that really can’t be done in SwiftUI, you can always switch back to UIKit as your last option. The following figure contains such an example of using UITextField in SwiftUI, including reacting to SwiftUI environment values and using new property wrappers, which makes final usage really SwiftUI-like.

Conclusion

To sum things up, SwiftUI can be used for any type of application, and I believe that it is much more efficient, readable, and fun, which is a win-win for both developers and businesses. Additionally, Apple’s effort to push SwiftUI forward indicates that it may become the main UI framework in the near future. With 5 months of intense experience, I personally don’t see any reason for developers to hold back.

References

Did you find this article useful? Share it on social media.

Need expert advice from our consultants?

Articles

CN Group

CN Group CZ a.s.
Prague Office 
Ve Smečkách 20 
110 00 Prague 1 
Czech Republic
Registration No.:
07885041

Locations
Contacts
Social Media
LinkedIn
Twitter
Xing
Facebook
YouTube
Instagram
Reviews on Clutch
clutch logo
© 2020-2022 CN Group CZ a.s., All rights reserved.
  • Sitemap
  • Legal Terms / Impressum
  • GDPR
  • Risk and Compliance