@Duncan: As I understand it, SwiftData model objects are not thread-safe, just like NSManagedObjects. Are there any additional mechanisms to make managing this easier for us than it was in traditional Core Data? e.g., compiler warnings before passing an object out of its context?
@Dave N (Apple): We have provided the ModelActor protocol & the DefaultModelExecutor to make SwiftData work with Swift Concurrency. Use your ModelContainer to initialize a ModelContext in the initializer for your ModelActor conforming actor object and use that context to initialize a DefaultModelExecutor. This will allow you to use that context with async functions on your actor.
@Ben T (Apple): Swift will enforce sendability requirements
@Duncan: SwiftData のモデルオブジェクトは NSManagedObject と同様にスレッドセーフではないと理解しています。従来の Core Data と比べて、オブジェクトを扱う際に管理しやすくするための追加のメカニズムはありますか?例えば、オブジェクトをそのコンテキストから出す前にコンパイラの警告があるでしょうか?
final class Card {
var id: UUID
var front: String
var back: String
init(front: String, back: String) {
self.id = UUID()
self.front = front
self.back = back
}
}
final class Card {
var front: String
var back: String
init(front: String, back: String) {
self.front = front
self.back = back
}
}
extension Card: Identifiable { }
ID (id) がない!
Playground で見てみます。
final class Card {
var front: String
var back: String
init(front: String, back: String) {
self.front = front
self.back = back
}
}
extension Card: Identifiable { }
let card = Card(front: "前", back: "後")
print(card.id)
print(card.front)
print(card.back)
// ObjectIdentifier(0x0000600000c014d0)
// 前
// 後
id が取れます。
Identifiable を継承しても同様です。
Apple のサンプルコードは少し省略して書きましたが、実際は以下のようなコードです。
final class Card: ObservableObject {
@Published var front: String
@Published var back: String
var creationDate: Date
init(front: String, back: String, creationDate: Date = .now) {
self.front = front
self.back = back
self.creationDate = creationDate
}
}
extension Card: Identifiable { }
struct CardCarousel: View {
@State private var selectedCardID: Card.ID? // *
@FocusState private var focusCardID: Card.ID?
private let initialCardID: Card.ID
let editing: Bool
var cards: [Card]
init(editing: Bool, cards: [Card], selectedCard: Card) {
self.editing = editing
self.cards = cards
initialCardID = selectedCard.id
}
var body: some View {
VStack {
ScrollView(.horizontal) {
LazyHStack(spacing: 0) {
ForEach(cards) { card in // *
Group {
if editing {
CardEditorView(card: card)
} else {
FlashCardView(card: card)
.id(card.id)
ObjectIdentifier(0x0000600000c014d0) の型は、
Card.ID
です。
また、List 内の ForEach() の引数は一つです。
便利ですよね!
🆔 SwiftData の場合
同じく Apple サンプルコードです。
SwiftData では更に便利になっています。
こちらにもモデルクラスに ID はありません。
Identifiable もありません。
@Model
final class Card {
var front: String
var back: String
var creationDate: Date
init(front: String, back: String, creationDate: Date = .now) {
self.front = front
self.back = back
self.creationDate = creationDate
}
}
struct CardCarousel: View {
@State private var selectedCardID: PersistentIdentifier? // *
@FocusState private var focusCardID: PersistentIdentifier?
private let initialCardID: PersistentIdentifier
let editing: Bool
var cards: [Card]
init(editing: Bool, cards: [Card], selectedCard: Card) {
self.editing = editing
self.cards = cards
initialCardID = selectedCard.id
}
var body: some View {
VStack {
ScrollView(.horizontal) {
LazyHStack(spacing: 0) {
ForEach(cards) { card in // *
Group {
if editing {
CardEditorView(card: card)
} else {
FlashCardView(card: card)
.id(card.id)