fatbobman / blogComments

1 stars 0 forks source link

SwiftData 中的并发编程 | 肘子的Swift记事本 #202

Open fatbobman opened 11 months ago

fatbobman commented 11 months ago

https://www.fatbobman.com/posts/concurret-programming-in-SwiftData/

在 Core Data 中进行并发编程可能并不困难,但是充满了陷阱。即使对 Core Data 有充分的经验,稍有疏忽也可能在代码中埋下隐患,从而使应用程序变得不安全。SwiftData 作为 Core Data 的继任者,提供了一种更加优雅、更加安全的并发编程机制。本文将介绍 SwiftData 是如何解决这些问题的,并为开发者提供更好的并发编程体验。

rezwits commented 5 months ago

Man Bob Fat! (i.e. great work!)

fatbobman commented 5 months ago

Man Bob Fat! (i.e. great work!)

@rezwits Thanks!

chinaysun commented 5 months ago

感谢分享。想请教一下,使用 self[identifier, as: T.self] 进行查证item是否存在 是否可靠?我尝试了一下在Xcode13.2 iOS17.4的环境下,在没有任何写入的data情况下,subscript不会返回nil。

fatbobman commented 5 months ago

@chinaysun ?你是否可以读取返回的 model 呢?没有写入还是没有创建?创建了没有持久化还是可以被获取的。

chinaysun commented 5 months ago

@fatbobman @chinaysun ?你是否可以读取返回的 model 呢?没有写入还是没有创建?创建了没有持久化还是可以被获取的。

可以读取返回的model,我想这是否就是问题的所在?在我看您写的updateItem method里,使用subscript去进行了判断object是否存在。那么,如果我们并没有插入一个model (无论是否已经持久化),我们直接调用updateItem method,那么这个updateItem method 是否应该抛出异常? 但我遇见的情况是,不会抛出异常, 因为有model返回。

fatbobman commented 5 months ago

@chinaysun 如果返回了一个不存在的数据,那绝对是 Bug,但是我想不出出现这个 Bug 的理由。如果可能,能否构建一个 Bug 的复现代码

chinaysun commented 5 months ago

@chinaysun 如果返回了一个不存在的数据,那绝对是 Bug,但是我想不出出现这个 Bug 的理由。如果可能,能否构建一个 Bug 的复现代码

嗯,据我的观察。它是一个bug。在unit test中应该很好复现。

let handler = DataHandler(container:container)
let item = Item(timestamp: .now)

let expect = expectation(description: "Should throw error")
 do {
            try await handler.updateItem(identifier: item.id, timestamp: .now )
            XCTFail("Should not update")
 } catch {
            expect.fulfill()
}

 await fulfillment(of: [expect])
fatbobman commented 5 months ago

@chinaysun 根据这个代码,SwiftData 的下标方法没有直接包装 existObject ,而是新增加了一层。这样才会在上下文之外,根据 id 就能获取数据。 感觉上不对,但是实际上,我也不能说它一定算是个 Bug。 如果可以更新,然后 insert, save ,那么就是 SwiftData 允许数据在上下文之外进行调整( 根据它对底层数据的上两层包装,这点说的通 )

chinaysun commented 5 months ago

@chinaysun 根据这个代码,SwiftData 的下标方法没有直接包装 existObject ,而是新增加了一层。这样才会在上下文之外,根据 id 就能获取数据。 感觉上不对,但是实际上,我也不能说它一定算是个 Bug。 如果可以更新,然后 insert, save ,那么就是 SwiftData 允许数据在上下文之外进行调整( 根据它对底层数据的上两层包装,这点说的通 )

我理解您的意思,如果更新一个不存在的object,那么swiftdata会进行调整是否需要insert一个新的?如果我理解您正确的意思话。但是这个写法会有异常抛出

CoreData: annotation: repairing validation failure Error Domain=NSCocoaErrorDomain Code=1560 "Multiple validation errors occurred."

fatbobman commented 5 months ago

@chinaysun 这样的话就是 Bug。如果通过下标方法获取到的数据 id 与创建时一致,说明获取途径可以绕过上下文( 正常不应该)。但是 update 又需要通过上下文。这样就出现了错误。 你可以提交一个 FB。

chinaysun commented 5 months ago

@chinaysun 这样的话就是 Bug。如果通过下标方法获取到的数据 id 与创建时一致,说明获取途径可以绕过上下文( 正常不应该)。但是 update 又需要通过上下文。这样就出现了错误。 你可以提交一个 FB。

感谢您的回复。另外想请教一下,我看您写的crud方法里都call 了 save()。想了解下,如果我们直接enable autosaveEnabled, 那么swiftdata应该能够自动handle persist了

fatbobman commented 5 months ago

@chinaysun 这样的话就是 Bug。如果通过下标方法获取到的数据 id 与创建时一致,说明获取途径可以绕过上下文( 正常不应该)。但是 update 又需要通过上下文。这样就出现了错误。 你可以提交一个 FB。

感谢您的回复。另外想请教一下,我看您写的crud方法里都call 了 save()。想了解下,如果我们直接enable autosaveEnabled, 那么swiftdata应该能够自动handle persist了

@chinaysun autosave 只在main context 中好用。

chinaysun commented 5 months ago

@fatbobman

@chinaysun 这样的话就是 Bug。如果通过下标方法获取到的数据 id 与创建时一致,说明获取途径可以绕过上下文( 正常不应该)。但是 update 又需要通过上下文。这样就出现了错误。 你可以提交一个 FB。

感谢您的回复。另外想请教一下,我看您写的crud方法里都call 了 save()。想了解下,如果我们直接enable autosaveEnabled, 那么swiftdata应该能够自动handle persist了

@chinaysun autosave 只在main context 中好用。

可能是我的理解有错误?希望您能分享下实践中的经验。autosave 只有在main context中被default to true, 如果自定义context中default value为false, 但是我们可以进行更改。

        let modelContext = ModelContext(modelContainer)
        modelContext.autosaveEnabled = true
fatbobman commented 5 months ago

@chinaysun swiftdata 在设置这个属性的时候考虑不周。改属性设置为true,仅对maincontext 有效,其他上下文设置为true 也不会自动保存。这是苹果工程师亲自确认的

chinaysun commented 5 months ago

@fatbobman @chinaysun swiftdata 在设置这个属性的时候考虑不周。改属性设置为true,仅对maincontext 有效,其他上下文设置为true 也不会自动保存。这是苹果工程师亲自确认的

万分感谢。这真是一个大坑啊。