Implement ModelActor for thread-safe SwiftData access
- Dominant language
- Swift
- Stars
- 0
- Forks
- 0
- Avg merge
- 1h 41m
- Merged PRs (30d)
- 1
Description
### Problem
Current SwiftData access pattern has concurrency safety issues:
- Models marked `@unchecked Sendable` without proper isolation
- Direct `ModelContext` access from multiple actors
- No structured concurrency boundaries
- Risk of data races and crashes
### Proposed Solution: ModelActor Pattern
#### Create ArkavoDataActor
```swift
@ModelActor
actor ArkavoDataActor {
func getOrCreateAccount() throws -> Account {
let descriptor = FetchDescriptor(predicate: #Predicate { $0.id == 0 })
if let account = try modelContext.fetch(descriptor).first {
return account
}
let account = Account()
modelContext.insert(account)
try modelContext.save()
return account
}
func fetchProfile(withPublicID publicID: Data) throws -> Profile? {
let descriptor = FetchDescriptor(
predicate: #Predicate { $0.publicID == publicID }
)
return try modelContext.fetch(descriptor).first
}
func saveThought(_ thought: Thought) throws -> Bool {
let existing = try modelContext.fetch(
FetchDescriptor(predicate: #Predicate { $0.publicID == thought.publicID })
)
guard existing.isEmpty else { return false }
modelContext.insert(thought)
try modelContext.save()
return true
}
}
```
#### Usage Pattern
```swift
class CreatorViewModel: ObservableObject {
@Published var videoThoughts: [Thought] = []
private let dataActor: ArkavoDataActor
init(container: ModelContainer) {
self.dataActor = ArkavoDataActor(modelContainer: container)
}
func loadVideoThoughts() async {
do {
let thoughts = try await dataActor.fetchThoughts(
forStreamPublicID: videoStreamPublicID
)
await MainActor.run {
self.videoThoughts = thoughts
}
} catch {
print("Error: \(error)")
}
}
}
```
### Benefits
- ✅ Structured concurrency with clear actor boundaries
- ✅ No `@unchecked Sendable` needed
- ✅ Compile-time actor isolation checking
- ✅ Prevents data races
- ✅ Centralized data access logic
### Implementation Checklist
- [ ] Create `ArkavoDataActor.swift` with `@ModelActor`
- [ ] Migrate database operations to actor methods
- [ ] Update `PersistenceController` to provide actor instances
- [ ] Update ViewModels to use actor pattern
- [ ] Remove `@unchecked Sendable` annotations
- [ ] Add concurrency tests
### Files to Create
- `ArkavoDataActor.swift`
### Files to Modify
- `PersistenceController.swift`
- `CreatorViewModel.swift`
- `VideoFeedViewModel.swift`
- `ChatViewModel.swift`
- `GroupViewModel.swift`
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reading PersistenceController.swift and the proposed ArkavoDataActor.swift structure, then review CreatorViewModel.swift, VideoFeedViewModel.swift, ChatViewModel.swift, and GroupViewModel.swift. Trace existing database operations and @unchecked Sendable annotations before planning the migration. Done means actor-based access is adopted, the listed view models are updated, unsafe annotations are removed, and concurrency tests are added.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- database, mobile
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100