With the introduction of SceneDelegate in iOS 13, some of you might be wondering where to place your code to start creating your app programmatically. Worry no more :-D, following steps will clarify all your doubts. Let’s quickly jump into the code and I will explain the code as we proceed.
Step: 1 – Project Creation
- Create an Xcode project


Step: 2 – Remove all storyboard settings from project
- Delete your Main storyboard (As we want to do everything programatically ;-))
- Go to General > Deployment Info > Remove Main

- Go to info.plist > Delete the item as show in the screenshot below

Step: 3 – Add your ViewController to SceneDelegate by adding following code to your SceneDelegate.swift. My ViewController class’ name is LoginViewController.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
self.window!.rootViewController = UINavigationController(rootViewController: LoginViewController())
self.window!.makeKeyAndVisible()
}
}
Step: 4 – Design your ViewController
Let’s design a traditional login screen with a UITextField to enter username, another UITextField to enter password with isSecureTextEntry = true and a UIButton to submit login credentials. And a UIStackView to align all the UIControls. To maintain the simplicity of this post, the login button will only push another ViewController on to the stack.
Go to your ViewController class and add the following code, in my case it’s LoginViewController.
import UIKit
class LoginViewController: UIViewController {
let usernameTF = UITextField()
let passwordTF = UITextField()
let loginBtn = UIButton()
let verticalStackView = UIStackView()
}
In the above code, we have created the UIControls required to design the Login screen. Let’s design each of the UIControls as following:
func configView() {
view.backgroundColor = .white
navigationController?.setNavigationBarHidden(true, animated: false)
}
func configUserNameTF() {
usernameTF.textColor = .red
usernameTF.borderStyle = .roundedRect
usernameTF.placeholder = "Username"
usernameTF.delegate = self
view.addSubview(usernameTF)
}
func configPasswordTF() {
passwordTF.borderStyle = .roundedRect
passwordTF.placeholder = "Password"
passwordTF.isSecureTextEntry = true
passwordTF.delegate = self
view.addSubview(passwordTF)
}
func configLoginBtn() {
loginBtn.setTitle("Login", for: .normal)
loginBtn.setTitleColor(.white, for: .normal)
loginBtn.backgroundColor = UIColor.green
loginBtn.addTarget(self, action: #selector(login), for: UIControl.Event.touchUpInside)
view.addSubview(loginBtn)
}
func configStackView() {
verticalStackView.addArrangedSubview(usernameTF)
verticalStackView.addArrangedSubview(passwordTF)
verticalStackView.addArrangedSubview(loginBtn)
verticalStackView.alignment = .fill
verticalStackView.distribution = .fillEqually
verticalStackView.axis = .vertical
verticalStackView.spacing = 20
view.addSubview(verticalStackView)
}
@objc func login() {
let welcomeText = "Hey " + usernameTF.text! + "...."
print(welcomeText)
let homeVC = HomeViewController()
homeVC.welcomeText = welcomeText
navigationController?.pushViewController(homeVC, animated: true)
}
}
extension LoginViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
}
You might be getting error in login() method. But we will fix that later. As the UI is quite simple therefore we are using UIStackView to align the UI. But to align UIStackView we need to configure it’s UI constraints. Following code will configure the constraints:
func configConstraints() {
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
verticalStackView.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor, constant: 50.0),
verticalStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
verticalStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
verticalStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
verticalStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0)
]
NSLayoutConstraint.activate(constraints)
}
Now add following methods:
override func viewDidLoad() {
super.viewDidLoad()
configUI()
}
func configUI() {
configView()
configUserNameTF()
configPasswordTF()
configLoginBtn()
configStackView()
configConstraints()
}
I like to keep code neat and readable therefore I try to segregate the code this way.
Now create a new ViewController class – HomeViewController by right clicking on one of your swift file > Cocoa Touch Class > SubClass of ViewController. Don’t forget to select language as Swift.
Once done, copy-paste following code in your class.
import UIKit
class HomeViewController: UIViewController {
let welcomeTextLbl = UILabel()
var welcomeText = ""
override func viewDidLoad() {
super.viewDidLoad()
configUI()
}
func configUI() {
configView()
configWelcomeText()
configConstraints()
}
func configView() {
view.backgroundColor = .white
navigationController?.setNavigationBarHidden(true, animated: false)
}
func configWelcomeText() {
welcomeTextLbl.text = welcomeText
welcomeTextLbl.textColor = .black
view.addSubview(welcomeTextLbl)
}
func configConstraints() {
welcomeTextLbl.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
welcomeTextLbl.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor, constant: 40.0),
welcomeTextLbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
welcomeTextLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0)
]
NSLayoutConstraint.activate(constraints)
}
}
That’s all..!!
Run the app and you should see your programmatically created app run flawlessly.
————————————————– END ————————————————–