List in SwiftUI with RxSwift
SwiftUI, Apple’s declarative framework for building user interfaces, pairs exceptionally well with RxSwift, a powerful framework for reactive programming. Together, they enable developers to create dynamic and responsive UIs effortlessly. In this article, we’ll build a simple SwiftUI app that demonstrates the integration of RxSwift for handling asynchronous data streams.
Prerequisites
Before we start, ensure you have the following:
- Xcode 11 or later
- Basic understanding of Swift, SwiftUI, and RxSwift
Setting Up the Project
Step 1: Create a New Project
- Open Xcode and create a new “Single View App” project.
- Name your project and ensure the language is set to Swift.
- Choose SwiftUI as the user interface.
Step 2: Install RxSwift and RxCocoa
- Close Xcode.
- Open Terminal and navigate to your project directory.
- Run
pod init
to create aPodfile
. - Open the
Podfile
and add the following lines:
target 'YourProjectName' do
use_frameworks!
pod 'RxSwift'
pod 'RxCocoa'
end
5. Install the pods by running pod install
.
6. Open the generated .xcworkspace
file to continue working on your project in Xcode.
Building the SwiftUI View
Step 1: Create the ViewModel
First, create a ViewModel that will handle the business logic using RxSwift.
import Foundation
import RxSwift
import RxCocoa
class CitySearchViewModel: ObservableObject {
@Published var searchText: String = ""
@Published var filteredCities: [String] = []
private let disposeBag = DisposeBag()
private let cities = ["New York", "Los Angeles", "Chicago", "Houston", "Phoenix", "Philadelphia", "San Antonio", "San Diego", "Dallas", "San Jose"]
init() {
setupBindings()
}
private func setupBindings() {
$searchText
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.map { [unowned self] query in
self.cities.filter { $0.lowercased().contains(query.lowercased()) }
}
.assign(to: &$filteredCities)
}
}
Step 2: Create the SwiftUI View
Now, create the SwiftUI view that will interact with the ViewModel.
import SwiftUI
struct CitySearchView: View {
@StateObject private var viewModel = CitySearchViewModel()
var body: some View {
NavigationView {
VStack {
TextField("Search", text: $viewModel.searchText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
List(viewModel.filteredCities, id: \.self) { city in
NavigationLink(destination: Text(city)) {
Text(city)
}
}
}
.navigationTitle("City Search")
}
}
}
struct CitySearchView_Previews: PreviewProvider {
static var previews: some View {
CitySearchView()
}
}
Explanation
- ViewModel Setup: The
CitySearchViewModel
class uses@Published
properties to automatically update the UI whensearchText
orfilteredCities
changes. ThesetupBindings
method sets up the binding forsearchText
, debouncing the input to reduce unnecessary filtering and usingremoveDuplicates
to avoid redundant updates. The filtered results are then assigned to thefilteredCities
property. - SwiftUI View: The
CitySearchView
struct defines the UI. It contains aTextField
for input and aList
to display the filtered cities. The@StateObject
attribute ensures that the view updates whenever the ViewModel's properties change.
Running the App
Build and run the app on the simulator or a physical device. You should see a text field at the top of the screen. As you type into the text field, the list below should update in real-time, showing cities that match the search query.
Conclusion
This article demonstrates how to integrate RxSwift with SwiftUI to build a dynamic, reactive user interface. By combining the power of RxSwift for handling asynchronous data streams and SwiftUI for declarative UI development, you can create highly responsive and maintainable applications. In order to learn Basic SwiftUI design creation follow these links: SimpleSwiftUI, LoginScreenSwiftUI.