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
- Run Xcode and select ‘Create a new Xcode project.’
- Select ‘App’ and click ‘Next.’
- Enter the Project Name, select ‘SwiftUI’ for Interface, and ‘Swift’ for Language.
- 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.