DEV Community

Cover image for Getting Started with ViewCode in iOS: A Basic Guide
Gustavo Guedes
Gustavo Guedes

Posted on

Getting Started with ViewCode in iOS: A Basic Guide

Hey everyone! How’s it going? The idea of this article is to provide a basic guide on how to create a project using the ViewCode approach.

If you’re not familiar with what ViewCode is, I’ll explain a bit below.

What problem does it solve?

The storyboard pattern, used to create interfaces in Xcode, is very cool and intuitive. However, when working in a team, this approach can cause a lot of headaches.

Basically, screens created with storyboard have an xml file that stores everything we insert or edit. Since these changes are not made programmatically, they can lead to many conflicts when working in a team.

There are other ways to avoid this problem, and one of them is using ViewCode. This approach involves creating the screen elements programmatically, via code, without relying on Interface Builder and storyboards.

What about SwiftUI?

SwiftUI is one of the alternatives to solve this problem. It brings a declarative language for creating screens and components, with a very interesting Live Preview. If you’ve used Jetpack Compose or Flutter before, you’ll notice some similarities.

However, SwiftUI is only available starting from iOS 13. Depending on your app’s target audience, this could be a limitation, as devices like the iPhone 6, 6 Plus, and earlier models won’t have access. You can check the minimum and maximum supported versions for Apple devices here.

Let’s get to work

01. Creating the project

To start, let’s open Xcode and create a new project. In this example, I selected the iOS/App option.

creating-project

Enter the project name and ensure the options are configured as follows:

Inferface: Storyboard
Language: Swift

setup-project

Choose where to save the project and that’s it! Now we can start coding.

During the creation of this article, I used Xcode version 15.3 (15E204a), and the latest available iOS version is 17.4.

Our project will look like this once Xcode opens it:

created-project

If you unchecked the “Include Tests” option, the Tests and UITests folders will not be present. But don’t worry, we won’t be using them in this article, and they can be created later if needed.

With the project open, we see that it has two .storyboard files: LaunchScreen.storyboard and Main.storyboard. The LaunchScreen is the screen displayed while the operating system loads resources for our app to function correctly. The Main is the main screen of our app.

The file that interests us at this point is Main.storyboard.

02. Initial changes

Delete the Main.storyboard file.

deleting-main-storyboard

Click on “Move to trash”.

move-to-trash

Now, let’s access the Target Properties settings of our application.

opening-info-file

With the settings open, delete the following lines:

“Main storyboard file base name”

info-01

e

"Application Scene Manisfest" > "Scene Configuration" > "Window Application Session Role" > "Item 0" > "Storyboard Name"

info-02

After making these changes, let’s access the SceneDelegate to configure the entry point of our application since we removed the storyboard references.

scene-delegate

We’ll make a few small changes to this file.

  1. Remove some comments and create our windowScene variable. It will be used to configure which controller/screen will be rendered.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
}
Enter fullscreen mode Exit fullscreen mode
  1. Configure the controller that will be displayed when the app starts::
let safeWindow = UIWindow(windowScene: windowScene)
safeWindow.frame = UIScreen.main.bounds
safeWindow.rootViewController = ViewController()
safeWindow.makeKeyAndVisible()

window = safeWindow
Enter fullscreen mode Exit fullscreen mode

At this stage, we create our window based on the scene provided by the guard let windowScene. Then, we configure the screen to occupy the entire available space and define the controller that will be used. Finally, we assign our safeWindow to the window variable.

This ViewController is the one created during the initial project setup

  1. Running the application

Now, by selecting one of the emulators and running the application (either by clicking the play button at the top or using the CMD + R command), we should see the following behavior:

selecting-emulator

running-app

What’s happening is:

  1. The LaunchScreen.storyboard file is displayed.
  2. The view of our controller is rendered. And since it has nothing in it, the screen appears blank.

If we access our ViewController and set a background color for the view, we’ll already see the change when running the project again:

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .red
}
Enter fullscreen mode Exit fullscreen mode

app-01

Now we’re all set to start building our application programmatically.

Creating elements with ViewCode

Creating screen elements is done entirely programmatically. But how do we do that?

Example:

private lazy var label: UILabel = {
    let label = UILabel()

    label.text = "Hello World"
    label.translatesAutoresizingMaskIntoConstraints = false

    return label
}()
Enter fullscreen mode Exit fullscreen mode

We can observe the following:

  1. We use the private keyword to ensure that no one outside our class can access this information.
  2. lazy is used so the variable only enters memory when it’s utilized.
  3. The {}() approach is a function that self-executes and returns the variable’s type element.
  4. translatesAutoresizingMaskIntoConstraints = false to prevent automatically generated constraint configurations from conflicting with the ones we manually configure.

It’s important to note that every element created programmatically needs the translatesAutoresizingMaskIntoConstraints = false configuration. Otherwise, conflicts may occur, and the elements might not behave as expected.

Now, we need to add this element to the screen.

override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = .white

    view.addSubview(label)
}
Enter fullscreen mode Exit fullscreen mode

We change the background of the view attached to our controller to white and add our label inside it.

To position our element:

NSLayoutConstraint.activate([
    label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
Enter fullscreen mode Exit fullscreen mode

Then run the application, and voilà:

hello-world

Conclusion

As mentioned at the beginning, this is a basic guide for creating projects using ViewCode. There are several improvements we can make, such as creating separate view files—after all, it’s not ideal to create these elements directly in our controller. But I wanted to keep this article concise and to the point. In the next one, we’ll explore element creation on the screen in more depth.

That’s it for today, folks. Thanks, and see you next time!

Let me know if you need any further adjustments!

Top comments (1)

Collapse
 
aneudysamparo profile image
Aneudys Amparo

Thanks, I’m using storyboards but the builder interface is very limited for some views. I’ll try this.
Btw nice info about SwiftUI minimum target.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.