SwiftUI style, iPhone app development, creating a to-do list using 12 table view controllers

Hello. In this post, we will explore how to develop an iPhone app using the Swift language with SwiftUI. Specifically, I will provide a detailed explanation of creating a to-do list flow using UITableViewController. We will compare the differences and use cases between SwiftUI and UIKit, and help you understand through hands-on practice.

1. Differences between SwiftUI and UIKit

SwiftUI is Apple’s new UI framework that helps you create user interfaces more intuitively. SwiftUI adopts a declarative programming approach, which is different from how you construct a UI using the traditional UIKit.

1.1 UI Composition

In UIKit, you manage each screen using ViewController, and you have to connect UIKit’s basic components directly in code or storyboard. In contrast, SwiftUI allows you to declare ‘views’ as constants and compose the screen by combining them. This means you can easily manage UI state changes.

1.2 State Management

SwiftUI simplifies state management by providing various property wrappers like @State, @Binding, and @ObservedObject. These features improve upon the complex logic previously required in UIKit, such as using Delegate patterns or NotificationCenter as needed.

2. Setting Up the Project

Let’s set up the project now. Open Xcode and create a new iOS app project.

2.1 Creating a New Project

  1. Run Xcode and select ‘Create a new Xcode project.’
  2. Select ‘App’ and click ‘Next.’
  3. Enter the Project Name, select ‘SwiftUI’ for Interface, and ‘Swift’ for Language.
  4. Click ‘Next,’ then choose a location to save the project.

3. Creating a To-Do List with SwiftUI

Now, let’s look into how to create a to-do list using SwiftUI. In this step, the to-do list will be managed as an array.

3.1 Creating the Data Model

First, we will define the data model for the to-do list. We create a simple structure as below.

struct Task: Identifiable {
    var id = UUID()
    var title: String
    var isCompleted: Bool
}
    

3.2 Adding a To-Do List Array

Now, we create an array that includes multiple to-do items.

class TaskStore: ObservableObject {
    @Published var tasks: [Task] = []
}
    

3.3 Creating the View

The view for the to-do list can be created using the List structure to display each task. Write the code as follows.

import SwiftUI

struct ContentView: View {
    @ObservedObject var taskStore = TaskStore()

    var body: some View {
        NavigationView {
            List {
                ForEach(taskStore.tasks) { task in
                    HStack {
                        Text(task.title)
                        Spacer()
                        if task.isCompleted {
                            Image(systemName: "checkmark")
                        }
                    }
                }
            }
            .navigationBarTitle("To-Do List")
            .navigationBarItems(trailing: Button(action: {
                // Logic to add a task
            }) {
                Image(systemName: "plus")
            })
        }
    }
}
    

3.4 Adding a Task

We will implement an add button so that users can add tasks. We will add an Alert to prompt the user for input.

@State private var showingAddTask = false
@State private var newTaskTitle = ""

Button(action: {
    showingAddTask.toggle()
}) {
    Image(systemName: "plus")
}
.alert(isPresented: $showingAddTask) {
    Alert(title: Text("Add New Task"),
          message: Text("Please enter the task title."),
          primaryButton: .default(Text("Add")) {
              let newTask = Task(title: newTaskTitle, isCompleted: false)
              taskStore.tasks.append(newTask)
              newTaskTitle = ""
          },
          secondaryButton: .cancel())
}
.textFieldAlert("Task Title", text: $newTaskTitle)
    

4. Creating a To-Do List with UITableViewController

Now, let’s implement the same functionality using UITableViewController with UIKit. We will include UIKit in the project and set up the UITableView.

4.1 Creating the UITableViewController Class

class TaskListViewController: UITableViewController {
    var tasks: [Task] = []
    
    // Initialize Data in viewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()
        // Add default data
        tasks.append(Task(title: "Example Task", isCompleted: false))
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tasks.count
    }

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

4.2 Setting Up Table View Cells

To set up the table view cells, we register a UITableViewCell and set the delegate and datasource.

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}

4.3 Adding a Task

As we used an Alert in the SwiftUI app, we can use UIAlertController to receive user input in UIKit.

@objc func addTask() {
    let alert = UIAlertController(title: "Add New Task", message: "Please enter the task title.", preferredStyle: .alert)
    alert.addTextField()
    
    let addAction = UIAlertAction(title: "Add", style: .default) { [weak self] _ in
        guard let title = alert.textFields?.first?.text else { return }
        let newTask = Task(title: title, isCompleted: false)
        self?.tasks.append(newTask)
        self?.tableView.reloadData()
    }
    
    alert.addAction(addAction)
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    present(alert, animated: true)
}
    

5. Conclusion

In this post, we explored the process of creating a to-do list app using SwiftUI and UIKit. SwiftUI offers greater intuition in UI composition and simplified state management, providing many conveniences for developers. Both UIKit and SwiftUI have their advantages, so it’s important to choose the appropriate framework based on the situation.

Thank you for reading this far, and if you have any additional questions or need assistance, please feel free to leave a comment.