@SenecaGlobal IT Services

Why SwiftUI has no ViewController?

Valibabu Shaik
6 min readMar 18, 2024

It’s been a while i wrote a post in medium , i have got stuck in my project works. it’s funny how time slips away, when we realise where are we 🤣…. Yes , i have Started My SwiftUI just few months back.. But anyway it’s not too late. Here onwards i would like to share my every thought or learning’s through medium . Let’s begin…

Lets define what is a View controller as per Apple Doc:

“A view controller manages a single root view, which may itself contain any number of subviews. User interactions with that view hierarchy are handled by your view controller, which coordinates with other objects of your app as needed.”

Of Course This might me a little odd 🤮 definition. Few people says that we know it bro .. 😋.

Yes ..! But i would like to explain this in my way of understanding 😀 .

Figure : #1 UIKit — Data Flow in a View Controller

Lets refer the above diagram :

Let’s say we have a view controller Called PlayerViewController , that owns multiple views like PlayerView and PlayButton along with a Boolean property called ‘isPlaying’ , that need to respond to user interaction by manually setting up target action , or defining a delegate

We have to observe the model change and respond to those event too.

Every time any values changes we have to read the value and set it everywhere it’s needed.

Lets see a small code snippet , may be i can explain you a bit more..

//
// PlayerViewController
//
// Created by Valibabu Shaik on 18/03/24.
//

import UIKit

protocol WidgetProtocol {
func playerView(isPlaying:Bool)
}


class PlayerViewController : UIViewController {

@IBOutlet private var payButton : UIButton!

@IBOutlet private var playerView : UIButton!

var isPlaying : Bool = false {
didSet {
playerView.backgroundColor = isPlaying ? .green : .blue
}
}

override func viewDidLoad() { super.viewDidLoad() }

@IBAction func clickOnPlay(_ action:UIButton) {
isPlaying = isPlaying ? false : true
}

}

extension PlayerViewController : WidgetProtocol {

func playerView(isPlaying: Bool) {
self.isPlaying = isPlaying ? false : true
}

}

So , if you see in the above code snippet , whenever ‘isPlaying’ property is changed by a playButton action or a WidgetProtocol function , i am making an imperative action to didSet method to update the ‘PlayerView’ background colour , means i am explicitly giving a dependency to render the View.

What if i had more View components depending on property change ?

As soon as the complexity of the app grows , it is welling up with a massive problem. I hope you understand the situation now..!

“The whole purpose of view controller is to sync your data in your view.”

“This is all complexity , that we have to manage 🤦.”

But not in Swift UI 💁‍♂️…. Lets go and see that too …🚀

In Swift we have few simple tools to define our data dependency and SwiftUI takes care of all the rest. But before going in to that , Let’s discuss few principles of Swift UI

1. Data Access as a Dependency ,

2. Source of truth.

Data Access as a Dependency :

Figure # 2

So, Every time you read the piece of data in your view , you’re creating a dependency for that view. Like we saw , i am updating playerView background colour whenever isPlaying Property is changes.

So , defining this dependency is a manual process and it can be quickly a complex endeavour.

Viewing SwiftUI is Declarative (Reactive) , data dependencies are as well. There is no Manual Synchronisation or invalidation is required

So , In Swift we simply describe data dependency to the framework using few tools called property wrappers and framework handle all the rest.

One of the tools (property wrappers) i would like to use to demonstrate the data dependency called @State. If you don’t know about what is property wrapper don’t worry , i would like to come up with a new story line soon, i really need to your support 👏 to do so 🙂.

Okay let’s get into the next principle ,

Source of Truth:

The source of truth can live in your view hierarchy , for example when we have some state, about something should be updated or not , or it can be external such as displaying a message coming from persistent model.

Regardless of where the source of truth live , you should always have ‘single source of truth’

Avoid Duplicated source of truth: Duplicated source of truth can lead to bug and inconsistency

Figure # 3 Duplicated Source of Truth

To avoid such Duplications or bug and inconsistency, what we shall do is to lift up the data in to a common ancestor and let the two children have a reference to it. When you have single source of truth , your eliminating inconsistency bug in between your view and your data , and we can use the tool available in the language to enforcing varient in your data.

single source of truth

So , In the above Code snippet (Scroll to top with PlayerViewController example with UIKit ) we can observe PlayerViewController had a dependency on source of truth property called “isPlaying”.

Lets see same example using SwiftUI framework…


//
// PlayerView.swift
//
// Created by Valibabu Shaik on 18/03/24.
//

import SwiftUI

PlayerView: View {

@State private var isPlaying : Bool = false

var body: some View {
ZStack {

Color(isPlaying ? .blue : .red)
.ignoresSafeArea()

Button(action: {
isPlaying.toggle()
}, label: {
Text("Play Button")
.foregroundStyle(.white)
})
}

}
}

#Preview {
PlayerView()
}

In the above code snippet , we are using property Wrapper called @State. , by doing this we are telling the system that “isPlaying” is a value that can change over time and that the playerView can depends on it.

So when the user taps on the button , value changes and framework will generate a body for this view.

Main Theory :

I understand that , this might a big story to read 😁. Let me start climax here 🧟‍ 🦸

When you use State , the framework allocate persistent storage for the variable on the view we have and track it as a dependency, because if the system is creating storage for you , we have always have to provide an initial constant value.

@State private var isPlaying : Bool = false

View can be recreated often by the system, but with state, the framework knows that it needs to persist the storage across multiple update of the same view.

Conclusion : 👨‍👩‍👦

SwiftUI addressed many of these challenges with its declarative approach.

SwiftUI is based on a data-driven framework. In SwiftUI, views are a function of state, not a sequence of events

So it does not require a ‘ VIEW CONTROLLER ‘…..

Thanks For reading my Article .. Feel free to comment on it , and i will correct it if any changes are need to added , Because i am also a new baby to this swift UI World.

Shaik Valibabu

skvalibabu@gmail.com

Module Lead in IOS App Development @Seneca_Global_IT_Services

--

--

Valibabu Shaik

Module Lead in IOS App Development at @Senecal Global IT Services