SwiftUI 中的领域:UI 中仅偶尔保存对象的实时文本
Posted
技术标签:
【中文标题】SwiftUI 中的领域:UI 中仅偶尔保存对象的实时文本【英文标题】:Realm in SwiftUI: Live Text in UI for Object Only Saved Occasionally 【发布时间】:2021-04-27 01:40:49 【问题描述】:我在一个 SwiftUI 应用程序中比较 Core Data 和 Realm,Core Data 做了一些我希望弄清楚如何在 Realm 中做的事情。
Core Data 让您可以随时更改对象,当它们在 SwiftUI 中为 ObservableObject
时,您的 UI 会立即更新。然后,只要您想保留更改,就保存 context
。
在 Realm 中,UI 中的对象是实时的,但除非您处于写入事务中,否则您无法更改它们。当实际的write
只是偶尔执行时,我试图让我的 UI 反映用户的实时/即时更改。下面是一个示例应用程序。
这是我的 Realm 模型:
import RealmSwift
class Item: Object, ObjectKeyIdentifiable
@objc dynamic var recordName = ""
@objc dynamic var text = ""
override class func primaryKey() -> String?
return "recordName"
这是我的视图模型,其中还包括我的 save()
函数,该函数仅每 3 秒保存一次。在我的实际应用中,这是因为这是一项昂贵的操作,并且在用户键入时执行此操作会使应用陷入爬行状态。
class ViewModel: ObservableObject
static let shared = ViewModel()
@Published var items: Results<Item>!
@Published var selectedItem: Item?
var token: NotificationToken? = nil
init()
//Add dummy data
let realm = try! Realm()
realm.beginWrite()
let item1 = Item()
item1.recordName = "one"
item1.text = "One"
realm.add(item1, update: .all)
let item2 = Item()
item2.recordName = "two"
item2.text = "Two"
realm.add(item2, update: .all)
try! realm.commitWrite()
self.fetch()
//Notifications
token = realm.objects(Item.self).observe [weak self] _ in
self?.fetch()
//Get Data
func fetch()
let realm = try! Realm()
self.items = realm.objects(Item.self)
//Save Data
var saveTimer: Timer?
func save(item: Item, text: String)
//Save occasionally
saveTimer?.invalidate()
saveTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) _ in
let realm = try! Realm()
try? realm.write(
item.text = text
)
最后,这是用户界面。它非常基本,反映了我试图实现这一点的应用程序的一般结构。
struct ContentView: View
@StateObject var model = ViewModel.shared
var body: some View
VStack
ForEach(model.items) item in
HStack
Button(item.text)
model.selectedItem = item
Divider()
ItemDetail(item: item)
...以及 ItemDetail 视图:
struct ItemDetail: View
@ObservedObject var item: Item
@StateObject var model = ViewModel.shared
init(item: Item)
self.item = item
var body: some View
//Binding
let text = Binding<String>(
get: item.text ,
set: model.save(item: item, text: $0)
)
TextField("Text...", text: text)
.textFieldStyle(RoundedBorderTextFieldStyle())
当我输入TextField
时,我如何让Button
文本反映我输入的内容实时考虑到我的realm.write
只发生每 3秒?我的Button
在写入后更新,但我希望 UI 能够实时响应——独立于写入。
【问题讨论】:
这是多用户应用还是单用户应用?此外,尚不清楚您为什么要获取对象,并且当发生更改时,您会再次获取它们。更改将自动反映在对象中,what 更改将反映在通知中。你为什么每 3 秒写一次 Realm?是什么阻止您在用户键入时使用字段中的文本简单地更新按钮文本?根本不需要领域。 这是一个多用户应用程序(虽然我没有使用 Realm Sync,如果这就是你所指的)。 当有更改时我会再次获取,因为它比处理单个更改更简单。 我每隔几秒钟就写一次,因为输入的文本会被处理并转换为 Base64 并且每次击键都非常慢(我必须等待几秒钟才能显示我键入的每个字母) . 如果我不需要 Realm 来反映更新的文本,那就太好了。但我不清楚如何。我是否设置了绑定并以某种方式将其值与保存到 Realm 的值相协调?我的问题的要点是如何做这样的事情。 【参考方案1】:根据Jay
的建议文档,我得到了以下工作,这要简单得多:
我的主视图添加了 @ObservedResults
属性包装器,如下所示:
struct ContentView: View
@StateObject var model = ViewModel.shared
@ObservedResults(Item.self) var items
var body: some View
VStack
ForEach(items) item in
HStack
Button(item.text)
model.selectedItem = item
Divider()
ItemDetail(item: item)
...然后ItemDetail
视图只使用@ObservedRealmObject
属性包装器,它绑定到 Realm 中的值并自动管理写入:
struct ItemDetail: View
@ObservedRealmObject var item: Item
var body: some View
TextField("Text...", text: $item.text)
.textFieldStyle(RoundedBorderTextFieldStyle())
这本质上是 Core Data 的工作方式(就视图代码而言),但 Realm 会自动保存到存储中。谢谢你,杰!
【讨论】:
天哪!好样的!非常高兴您有解决方案。 我要补充一点,这在我设计的示例中非常有效,但我在更复杂的实现中遇到了两件事:(1) 我宁愿在其中定义我的Results
,并且从视图模型中读取。 (2) 如何使用.filter()
和.sorted()
对@ObservedResults
执行更复杂的查询?以上是关于SwiftUI 中的领域:UI 中仅偶尔保存对象的实时文本的主要内容,如果未能解决你的问题,请参考以下文章
Firebase 引用对象不会保存到 SwiftUI 中的变量
当我绑定它的值时,SwiftUI TextField 的行为很奇怪(不能输入中文,偶尔退格会跳过一个字符)
核心数据对象仍然保存在presentationMode SwiftUI中的dismiss/cancel