Using SwiftUI's declarative syntax, building user interfaces for any of Apple's platforms is fast and exceptionally simple.
Firebase makes developing the backend for your app a lot easier by providing BaaS features such as a NoSQL database, a flexible authentication solution, as well as a serverless environment to extend you app with custom backend code.
Both SwiftUI and Firebase make developing apps a lot easier, but how do you bring both together?
In this talk, I'm going to build a simple, data-driven SwiftUI application that uses Cloud Firestore to store data.
You will learn:
* How to architect your SwiftUI app so both its local and remote state stay in sync in real time.
* How to use Firebase Authentication to give users a great out-of-the-box experience without having to sign in first.
* How to implement Sign in with Apple in less than 5 minutes using FirebaseUI!
1. Building SwiftUI Apps with
Firebase
Peter Friese, Developer Advocate, Google
@peterfriese
2. 🎉 JewelCase app demo
🤯 SwiftUI concepts
😅 Live coding: implementing a list in SwiftUI
🚰 Data Flow & Source of Truth
🔥 Firebase & Firestore Overview
🚶 Walk-through: Fetching data in real time from Firestore
Agenda
6. SwiftUI
• A declarative way to build your UI
• Everything is a view
• Every SwiftUI view is a struct
• You build UIs by composing views
• Views are a function of their state
Better state management!
16. struct DetailsView: View {
let movie: Movie
var body: some View {
ScrollView(.vertical) {
VStack(alignment: .leading) {
Text(movie.title).font(.title)
Text(movie.description).font(.body)
}
.padding()
}
.edgesIgnoringSafeArea(.all)
.background(Color(UIColor.secondarySystemBackground)
.edgesIgnoringSafeArea(.all))
}
}
Data Flow - Property
17. struct DetailsView: View {
let movie: Movie
var body: some View {
ScrollView(.vertical) {
VStack(alignment: .leading) {
Text(movie.title).font(.title)
Text(movie.description).font(.body)
}
.padding()
}
.edgesIgnoringSafeArea(.all)
.background(Color(UIColor.secondarySystemBackground)
.edgesIgnoringSafeArea(.all))
}
}
Data Flow - Property
Use for data thatdoesn’t change
18. struct GridView: View {
let movies: [Movie]
@State private var selection: Movie? = nil
var body: some View {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(movies) { movie in
if (movie.id "!= selection"?.id) {
CardView(movie: movie)
.onTapGesture { select(movie) }
.matchedGeometryEffect(id: movie.id, in: ns)
}
else {
CardView(movie: movie)
.opacity(0)
}
Data Flow - @State
19. struct GridView: View {
let movies: [Movie]
@State private var selection: Movie? = nil
var body: some View {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(movies) { movie in
if (movie.id "!= selection"?.id) {
CardView(movie: movie)
.onTapGesture { select(movie) }
.matchedGeometryEffect(id: movie.id, in: ns)
}
else {
CardView(movie: movie)
.opacity(0)
}
Data Flow - @State
20. struct GridView: View {
let movies: [Movie]
@State private var selection: Movie? = nil
var body: some View {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(movies) { movie in
if (movie.id "!= selection"?.id) {
CardView(movie: movie)
.onTapGesture { select(movie) }
.matchedGeometryEffect(id: movie.id, in: ns)
}
else {
CardView(movie: movie)
.opacity(0)
}
Data Flow - @State
Use for UI state
21. struct DiscoverMoviesView: View {
@StateObject var viewModel = DiscoverViewModel()
@Environment(.presentationMode) var presentationMode
@EnvironmentObject var movieStore: MovieStore
var body: some View {
NavigationView {
VStack {
SearchBar(text: $viewModel.searchText)
List {
ForEach(viewModel.tmdbMovies) { item in
Data Flow - @StateObject
22. struct DiscoverMoviesView: View {
@StateObject var viewModel = DiscoverViewModel()
@Environment(.presentationMode) var presentationMode
@EnvironmentObject var movieStore: MovieStore
var body: some View {
NavigationView {
VStack {
SearchBar(text: $viewModel.searchText)
List {
ForEach(viewModel.tmdbMovies) { item in
Data Flow - @StateObject
Use for viewmodels
23. struct DiscoverMoviesView: View {
@EnvironmentObject var movieStore: MovieStore
func addMovie(movie: TMDBMovie) {
print("Adding (movie.title)")
let newMovie = Movie(from: movie)
movieStore.addMovie(newMovie)
dismiss()
}
}
Data Flow - @EnvironmentObject
24. struct DiscoverMoviesView: View {
@EnvironmentObject var movieStore: MovieStore
func addMovie(movie: TMDBMovie) {
print("Adding (movie.title)")
let newMovie = Movie(from: movie)
movieStore.addMovie(newMovie)
dismiss()
}
}
Data Flow - @EnvironmentObject
Use for passingstuff down
48. let db = Firestore.firestore()
do {
_ = try db.collection(“movies")
.addDocument(from: movie)
}
catch {
print(“Error: (error.localizedDescription).")
}
Saving Data to Firestore
49. let db = Firestore.firestore()
do {
_ = try db.collection(“movies")
.addDocument(from: movie)
}
catch {
print(“Error: (error.localizedDescription).")
}
Saving Data to Firestore