0
0
iOS Swiftmobile~20 mins

Empty state handling in iOS Swift - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Tasks List
Shows a list of tasks. When there are no tasks, it shows a friendly empty state message with an icon and a button to add a new task.
Target UI
----------------------------------
|          Tasks List             |
|--------------------------------|
|                                |
|   [📋]                        |
|                                |
|   No tasks yet!                |
|   Tap the button below to add |
|   your first task.             |
|                                |
|          [Add Task]            |
----------------------------------
Display a navigation bar with title 'Tasks List'.
Show a list of tasks if any exist.
If the task list is empty, show a centered icon (use system image 'doc.text'), a title 'No tasks yet!', a subtitle 'Tap the button below to add your first task.', and a button labeled 'Add Task'.
Tapping 'Add Task' adds a new task to the list and updates the UI to show the list instead of the empty state.
Use UIKit and Swift.
Layout should be centered and look good on all iPhone screen sizes.
Starter Code
iOS Swift
import UIKit

class TasksViewController: UIViewController {
    private var tasks: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        title = "Tasks List"

        // TODO: Add your code here to show tasks or empty state
    }
Task 1
Task 2
Task 3
Task 4
Solution
iOS Swift
import UIKit

class TasksViewController: UIViewController, UITableViewDataSource {
    private var tasks: [String] = []

    private let tableView = UITableView()
    private let emptyStateView = UIView()
    private let emptyImageView = UIImageView()
    private let emptyTitleLabel = UILabel()
    private let emptySubtitleLabel = UILabel()
    private let addButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        title = "Tasks List"

        setupTableView()
        setupEmptyStateView()
        updateUI()
    }

    private func setupTableView() {
        tableView.dataSource = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

    private func setupEmptyStateView() {
        emptyStateView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(emptyStateView)
        NSLayoutConstraint.activate([
            emptyStateView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            emptyStateView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            emptyStateView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 20),
            emptyStateView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -20)
        ])

        emptyImageView.translatesAutoresizingMaskIntoConstraints = false
        emptyImageView.image = UIImage(systemName: "doc.text")
        emptyImageView.tintColor = .systemGray
        emptyImageView.contentMode = .scaleAspectFit
        emptyStateView.addSubview(emptyImageView)

        emptyTitleLabel.translatesAutoresizingMaskIntoConstraints = false
        emptyTitleLabel.text = "No tasks yet!"
        emptyTitleLabel.font = UIFont.preferredFont(forTextStyle: .title2)
        emptyTitleLabel.textAlignment = .center
        emptyTitleLabel.textColor = .label
        emptyStateView.addSubview(emptyTitleLabel)

        emptySubtitleLabel.translatesAutoresizingMaskIntoConstraints = false
        emptySubtitleLabel.text = "Tap the button below to add your first task."
        emptySubtitleLabel.font = UIFont.preferredFont(forTextStyle: .body)
        emptySubtitleLabel.textAlignment = .center
        emptySubtitleLabel.textColor = .secondaryLabel
        emptySubtitleLabel.numberOfLines = 0
        emptyStateView.addSubview(emptySubtitleLabel)

        addButton.translatesAutoresizingMaskIntoConstraints = false
        addButton.setTitle("Add Task", for: .normal)
        addButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
        addButton.addTarget(self, action: #selector(addTaskTapped), for: .touchUpInside)
        emptyStateView.addSubview(addButton)

        NSLayoutConstraint.activate([
            emptyImageView.centerXAnchor.constraint(equalTo: emptyStateView.centerXAnchor),
            emptyImageView.topAnchor.constraint(equalTo: emptyStateView.topAnchor),
            emptyImageView.widthAnchor.constraint(equalToConstant: 80),
            emptyImageView.heightAnchor.constraint(equalToConstant: 80),

            emptyTitleLabel.topAnchor.constraint(equalTo: emptyImageView.bottomAnchor, constant: 16),
            emptyTitleLabel.leadingAnchor.constraint(equalTo: emptyStateView.leadingAnchor),
            emptyTitleLabel.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor),

            emptySubtitleLabel.topAnchor.constraint(equalTo: emptyTitleLabel.bottomAnchor, constant: 8),
            emptySubtitleLabel.leadingAnchor.constraint(equalTo: emptyStateView.leadingAnchor),
            emptySubtitleLabel.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor),

            addButton.topAnchor.constraint(equalTo: emptySubtitleLabel.bottomAnchor, constant: 20),
            addButton.centerXAnchor.constraint(equalTo: emptyStateView.centerXAnchor),
            addButton.bottomAnchor.constraint(equalTo: emptyStateView.bottomAnchor)
        ])
    }

    private func updateUI() {
        if tasks.isEmpty {
            tableView.isHidden = true
            emptyStateView.isHidden = false
        } else {
            tableView.isHidden = false
            emptyStateView.isHidden = true
            tableView.reloadData()
        }
    }

    @objc private func addTaskTapped() {
        let newTask = "Task \(tasks.count + 1)"
        tasks.append(newTask)
        updateUI()
    }

    // MARK: - UITableViewDataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tasks.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
        cell.textLabel?.text = tasks[indexPath.row]
        return cell
    }

This solution uses UIKit to build a simple tasks list screen.

We create a UITableView to show tasks when the list is not empty.

We also create a custom empty state view with an icon, title, subtitle, and a button.

The updateUI() method switches between showing the table or the empty state depending on whether the tasks array is empty.

Tapping the 'Add Task' button adds a new task to the array and refreshes the UI to show the list.

All views use Auto Layout to center and size properly on all iPhone screens.

Final Result
Completed Screen
----------------------------------
|          Tasks List             |
|--------------------------------|
|                                |
|   [📋]                        |
|                                |
|   No tasks yet!                |
|   Tap the button below to add |
|   your first task.             |
|                                |
|          [Add Task]            |
----------------------------------
When the app starts, the empty state is visible because there are no tasks.
Tapping the 'Add Task' button adds 'Task 1' to the list and switches the view to show the table with one row labeled 'Task 1'.
Each subsequent tap adds another task with incremented number and updates the list.
The empty state disappears once there is at least one task.
Stretch Goal
Add swipe-to-delete functionality to remove tasks from the list.
💡 Hint
Implement UITableViewDelegate's editing methods and update the tasks array accordingly.