SwiftUI和Firebase的应用架构 (Application Architecture for SwiftUI & Firebase)
SwiftUI is an exciting new way to build UIs for iOS and Apple’s other platforms. By using a declarative syntax, it allows developers to separate concerns and focus on what’s relevant.
SwiftUI是一种令人激动的新方法,可为iOS和Apple的其他平台构建UI。 通过使用声明性语法,它使开发人员可以分离关注点并专注于相关内容。
As with everything new, it sometimes takes a while to get used to how things are done in the new world. I often see people try to cram too many things into their SwiftUI views, resulting in less readable code that doesn’t work well.
与所有新事物一样,有时需要一段时间才能习惯新世界中的事物处理方式。 我经常看到人们尝试将太多东西塞进他们的SwiftUI视图中,导致可读性差的代码无法正常工作。
It’s time to shake off the old habits of building MVCs (massive view controllers), folks!
是时候摆脱人们建立MVC(大规模视图控制器)的旧习惯了!
In this blog post I’m going to show you a clean way to connect your SwiftUI app to Firebase and fetch data from Cloud Firestore.
在这篇博客文章中,我将向您展示一种将SwiftUI应用连接到Firebase并从Cloud Firestore提取数据的干净方法。
示例应用 (The sample app)
To get us started, consider the following app which displays a list of books:
为使我们开始使用,请考虑以下显示图书清单的应用程序:
Hard to believe, but in less than 40 lines of code, we’re able to not only define a simple data model for books, as well as some sample data, but also a screen that displays the books in a list — that’s the power of SwiftUI!
难以置信,但是用不到40行代码,我们不仅可以为书籍定义一个简单的数据模型以及一些样本数据,而且还可以通过一个屏幕在列表中显示书籍-这就是功能SwiftUI!
添加Firebase (Adding Firebase)
To fetch data from Firestore, you’ll first have to connect your app to Firebase. I’m not going to go into great detail about this here — if you’re new to Firebase (or your background is in Android or web development), check out this video which will walk you through the process (don’t worry, it’s not very complicated).
要从Firestore获取数据,您首先必须将您的应用程序连接到Firebase。 我不会在这里对此进行详细介绍-如果您是Firebase的新手(或者您的背景是Android或网络开发),请观看此视频,它会逐步引导您(不要担心,这不是很复杂)。
Data in Firestore is stored in documents that contain a number of attributes. Documents are stored in collections. You cannot nest collections, but a document can contain collections, making it possible to create hierarchical data structures.
Firestore中的数据存储在包含许多属性的文档中。 文档存储在集合中。 您不能嵌套集合,但是文档可以包含集合,从而可以创建分层数据结构。
For our application, we will just use a simple collection named books
, which contains a number of documents that will represent our books. Each document will be made up of the following attributes:
对于我们的应用程序,我们将只使用一个名为books
的简单集合,其中包含许多代表我们的书的文档。 每个文档将由以下属性组成:
title
:string
title
:string
author
:string
author
:string
pages
:number
pages
:number
提取数据并订阅更新 (Fetching data and subscribing to updates)
Firestore does support one-time fetch queries, but it really shines when you use its realtime synchronisation to update data on any connected device. No longer will you have to implement pull-to-refresh — all data is kept in sync on all devices all of the time! Even better: the Firestore SDKs provide offline support out of the box, so all changes that the user made while their device was offline will automatically be synced back to Cloud Firestore once the device comes back online again.
Firestore确实支持一次性获取查询,但是当您使用其实时同步更新任何已连接设备上的数据时,它确实会发光。 您不再需要实施“按需刷新”,所有数据始终在所有设备上保持同步! 更好的是:Firestore SDK提供了开箱即用的离线支持,因此,一旦设备再次联机,用户在其设备脱机时所做的所有更改将自动同步回Cloud Firestore。
Implementing all of this isn’t even particularly complicated — quite the opposite, as you will see. Offline support is enabled by default, and implementing real-time sync is a matter of registering a snapshot listener to a Firestore collection you’re interested in.
实现所有这些甚至还不是特别复杂-就像您将看到的相反。 默认情况下会启用离线支持,而实现实时同步则只需将快照侦听器注册到您感兴趣的Firestore集合中即可。
The boilerplate for registering a snapshot listener for the books collection in our sample app looks like this:
在示例应用程序中为books集合注册快照侦听器的样板如下所示:
But where’s a good place to put the snapshot listener? After everything I told you about massive view controllers, you’re probably guessing it won’t be in the view itself — and you’re absolutely right!
但是放置快照监听器的好地方在哪里? 在我告诉您有关大型视图控制器的所有内容之后,您可能会猜想它不会出现在视图本身中,而且您绝对正确!
实施视图模型 (Implementing the view model)
A good way to keep our views clean and lean is to use an MVVM (Model, View, View Model) architecture. We’ve already got the view ( BooksListView
) and model ( Book
), so all that's missing is the view model.
保持视图整洁的一个好方法是使用MVVM(模型,视图,视图模型)体系结构。 我们已经有了视图( BooksListView
)和模型( Book
),因此缺少的只是视图模型。
The primary responsibility of the view model is to provide access to the data we want to display in our UI. This is typically done in a view-specific way: we might want to display the list of books in two different ways: a list view and a cover flow. The list might display more details about each book (such as number of pages as well as the author’s name), whereas the cover flow would display gorgeous book covers, with just the book title. Both views need different attributes from the model, so the view models would expose different attributes (and the view model for the cover flow might also include code to fetch large book cover art).
视图模型的主要职责是提供对我们要在UI中显示的数据的访问。 通常,这是通过特定于视图的方式完成的:我们可能希望以两种不同的方式显示书籍列表:列表视图和封面流程。 该列表可能会显示有关每本书的更多详细信息(例如页数和作者的姓名),而封面流程将显示精美的书封面以及仅书名。 两种视图都需要与模型具有不同的属性,因此视图模型将公开不同的属性(并且封面流程的视图模型可能还包含用于获取大型书籍封面的代码)。
A secondary responsibility of the view model is the provisioning of the data. In our simple application, we will handle data access directly in the view model, but in a more complex application I’d definitely recommend extracting this into a store or repository to make data access reusable across multiple view models.
视图模型的次要职责是提供数据。 在我们简单的应用程序中,我们将直接在视图模型中处理数据访问,但是在更复杂的应用程序中,我绝对建议将其提取到存储或存储库中,以使数据访问可在多个视图模型中重用。
To be able to use the view model in a SwiftUI view and subscribe to the data it manages, it needs to implement the ObservableObject
protocol, and all properties that we want our UI to be able to listen to need to be flagged using the @Published
property wrapper.
为了能够在SwiftUI视图中使用视图模型并订阅其管理的数据,它需要实现ObservableObject
协议,并且我们希望UI能够侦听的所有属性都需要使用@Published
进行标记属性包装器。
Here is the boilerplate for our view model:
这是我们的视图模型的样板:
With this in place, we can now add the code for registering the snapshot listener, and map the documents we receive into Book
instances:
有了这个,我们现在可以添加用于注册快照侦听器的代码,并将收到的文档映射到Book
实例中:
在SwiftUI视图中使用ViewModel (Using the ViewModel in a SwiftUI view)
Back in the BooksListView, we need to make two changes to use BooksViewModel
instead of the static list of books:
回到BooksListView,我们需要进行两项更改以使用BooksViewModel
而不是静态的图书列表:
By using the @ObservedObject
property wrapper (1), we tell SwiftUI to subscribe to the view model and invalidate (and re-render) the view whenever the observed object changes. And finally, we can connect the List view to the books
property on the view model (2), and get rid of the local book
array. Once the view appears, we can tell the view model to subscribe to the collection. Any changes that the user (and anyone else) makes to the books
collection in Firestore will now be reflected in the app's UI in realtime.
通过使用@ObservedObject
属性包装器(1),我们告诉SwiftUI订阅视图模型,并在观察到的对象发生变化时使视图无效(并重新渲染)。 最后,我们可以将List视图连接到视图模型(2)上的books
属性,并摆脱本地的book
数组。 视图出现后,我们可以告诉视图模型订阅该集合。 用户(和其他任何人)对Firestore中的books
集所做的任何更改现在都将实时反映在应用程序的UI中。
结论 (Conclusion)
With just a few lines of code, we’ve managed to connect an existing app to Firebase, subscribe to a collection of documents in Firestore and display any updates in real time.
仅需几行代码,我们就可以将现有应用程序连接到Firebase,在Firestore中订阅文档集合,并实时显示所有更新。
The key for a clean architecture is to extract the data access logic into a dedicated view model, and harness SwiftUI’s and Combine’s power to drive UI updates effortlessly.
干净的体系结构的关键是将数据访问逻辑提取到专用的视图模型中,并利用SwiftUI和Combine的功能轻松驱动UI更新。
从这往哪儿走 (Where to go from here)
If you’d like to learn more about Firestore, check out the Get to know Cloud Firestore series by @ToddKerpelman.
如果您想了解有关Firestore的更多信息,请查看@ToddKerpelman的“ 了解Cloud Firestore”系列 。
Interested in seeing how to build a real world application using Firestore and SwiftUI? Check out my multi-part blog post series in which I rebuild the iOS Reminders app using SwiftUI and Firebase:
有兴趣了解如何使用Firestore和SwiftUI构建真实的应用程序吗? 查看我的博客文章系列,其中我使用SwiftUI和Firebase重建iOS Reminders应用程序:
Replicating the iOS Reminders App using SwiftUI, Combine, and Firebase (Part 1)
Replicating the iOS Reminders App, Part 2: Connecting SwiftUI and Cloud Firestore
Replicating the iOS Reminders App, Part 3: Sign in with Apple using SwiftUI and Firebase
Next week, we’re going to look into how to make mapping DocumentSnapshots easier and more type-safe using the Codable protocol — stay tuned!
下周,我们将研究如何使用Codable协议使MapSnap DocumentSnapshot的映射更容易且类型更安全-请继续关注!
Originally published at https://peterfriese.dev/swiftui-firebase-fetch-data/.
最初在 https://peterfriese.dev/swiftui-firebase-fetch-data/ 发布 。
翻译自: https://medium.com/firebase-developers/swiftui-fetching-data-from-firestore-in-real-time-d95a020e78f