Create an iOS app programmatically

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
projecttype
Give a name to your 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
infoplist

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 ————————————————–

Leave a Reply

Your email address will not be published. Required fields are marked *