How to create a new Xcode project without Storyboard iOS 25.07.2020

Following steps are good for Xcode 11 and above.

  1. Delete Main.storyboard file and make sure you select "Move to trash" option to remove it completely.
  2. Remove reference to Main.storyboard.
    1. Click on your project root level on the left panel
    2. Select your app target
    3. Click General tab
    4. Under Deployment Info section you will find Main Interface field
    5. Delete "Main" and leave it blank
  3. Remove new Info.plist key-value, UISceneStoryboardFile. Open your Info.plist
    1. Click the arrow at the leftmost of Application Scene Manifest (UIApplicationSceneManifest) key to expand
    2. Click the arrow at the leftmost of Scene Configuration (UISceneConfigurations) key to expand
    3. Click the arrow at the leftmost of Application Session Role (UIWindowSceneSessionRoleApplication) key to expand
    4. Click the arrow at the leftmost of First Item (Item 0) key to expand
    5. Remove the key Storyboard Name (UISceneStoryboardFile)
  4. We need to initialize window and set rootViewController manually. Open SceneDelegate and add following snippet.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }

    let window = UIWindow(windowScene: windowScene)
    let nvc = UINavigationController(rootViewController: ViewController())
    window.rootViewController = nvc
    window.makeKeyAndVisible()
    self.window = window
}

Following is example of ViewController.

import UIKit
import SnapKit

class ViewController: UIViewController {
    lazy var btn: UIButton = {
        let btn = UIButton(type: .system)
        btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
        btn.setTitle("Go", for: .normal)
        btn.layer.cornerRadius = 8.0
        btn.layer.masksToBounds = true
        btn.tintColor = .white
        btn.backgroundColor = .red
        btn.addTarget(self, action: #selector(onButtonTapped), for: .touchUpInside)
        return btn
    }()

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

    @objc func onButtonTapped(sender: UIButton!) {
        print("onButtonTapped")
    }

    func setupUI() {
        title = "Start"
        self.view.backgroundColor = .systemBackground
        self.view.addSubview(btn)

        btn.snp.makeConstraints { (make) -> Void in
            make.centerY.equalTo(self.view)
            make.centerX.equalTo(self.view)
        }
    }
}

// MARK: - SwiftUI
import SwiftUI

struct MyViewProvider: PreviewProvider {
    static var previews: some View {
        Group {
            Group {
                ContainerView().edgesIgnoringSafeArea(.all)
                    .previewDevice(PreviewDevice(rawValue: "iPhone 11 Pro"))
                    .previewDisplayName("iPhone 11 Pro")

                ContainerView().edgesIgnoringSafeArea(.all)
                    .previewDevice(PreviewDevice(rawValue: "iPhone 7"))
                    .previewDisplayName("iPhone 7")
            }
        }
    }

    struct ContainerView: UIViewControllerRepresentable {
        let viewController = ViewController()

        func makeUIViewController(context: UIViewControllerRepresentableContext<MyViewProvider.ContainerView>) -> ViewController {
            return viewController
        }
        func updateUIViewController(_ uiViewController: MyViewProvider.ContainerView.UIViewControllerType, context: UIViewControllerRepresentableContext<MyViewProvider.ContainerView>) {
        }
    }
}