Dear all,
I'm building an app leveraging SwiftData and I have the following two classes:
Stagione:
import SwiftData
@Model
class Stagione {
@Attribute(.unique) var idStagione: String
var categoriaStagione: String
var miaSquadra: String
@Relationship(deleteRule: .cascade) var rosa: [Rosa]?
@Relationship(deleteRule: .cascade) var squadra: [Squadre]?
@Relationship(deleteRule: .cascade) var partita: [CalendarioPartite]?
init(idStagione: String, categoriaStagione: String, miaSquadra: String) {
self.idStagione = idStagione
self.categoriaStagione = categoriaStagione
self.miaSquadra = miaSquadra
}
}
Squadre:
import SwiftData
@Model
class Squadre {
var squadraCampionato: String
var stagione: Stagione?
init(squadraCampionato: String) {
self.squadraCampionato = squadraCampionato
}
}
Now, I have a view in which I'm calling a sheet to insert some Squadre:
// Presenta il foglio per aggiungere una nuova partita
GroupBox(label: Text("Dettagli Partita").font(.headline).padding()) {
VStack {
HStack {
Text("Giornata:")
TextField("Giornata", text: $idGiornata)
.frame(width: 30)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
DatePicker("Data Partita:", selection: $dataPartita, displayedComponents: .date)
.padding()
HStack {
Text("Squadra Casa:")
.frame(width: 150)
TextField("Squadra Casa", text: $squadraCasa)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("Gol Casa", text: $golCasa)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
HStack {
Text("Squadra Trasferta:")
.frame(width: 150)
TextField("Squadra Trasferta", text: $squadraTrasferta)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TextField("Gol Trasferta", text: $golTrasferta)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
HStack {
Button("Salva") {
if let partitaSelezionata = partitaSelezionata {
// Se è stata selezionata una partita, aggiorna i suoi dati
if let index = partite.firstIndex(where: { $0.id == partitaSelezionata.id }) {
partite[index].idGiornata = Int(idGiornata) ?? 0
partite[index].dataPartita = dataPartita
partite[index].squadraCasa = squadraCasa
partite[index].golCasa = Int(golCasa) ?? 0
partite[index].squadraTrasferta = squadraTrasferta
partite[index].golTrasferta = Int(golTrasferta) ?? 0
}
} else {
// Altrimenti, aggiungi una nuova partita
aggiungiPartita(stagione: stagione)
}
// Chiudi il foglio di presentazione
mostraAggiungiPartita = false
// Resetta il campo di input
idGiornata = ""
dataPartita = Date()
squadraCasa = ""
golCasa = ""
squadraTrasferta = ""
golTrasferta = ""
}
.buttonStyle(.borderedProminent)
.disabled(idGiornata.isEmpty || squadraCasa.isEmpty || squadraTrasferta.isEmpty || golCasa.isEmpty || golTrasferta.isEmpty)
// Bottone Chiudi
Button("Chiudi") {
mostraAggiungiPartita = false
}
.buttonStyle(.borderedProminent)
}
}
.padding()
}
}
I'd like to insert a autocomplete function in the textfields "Squadra Casa" and "Squadra Trasferta", based on the list of Squadre contained in the class "Squadre" and filtered for a specific Stagione.
Has anybody of you made something similar? Do you have any suggestions or code example which I can use?
Thanks,
A.
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
I am following this document from Apple to implement sharing with CloudKit. In it, Apple says
NSPersistentCloudKitContainer uses CloudKit zone sharing to share objects. Each share has its own record zone on the CloudKit server. CloudKit has a limit on how many record zones a database can have.
What is the record zone limit for a private CloudKit database?
I can find information about record and participant limits but not on record zone limits.
How can we identify whether the remote change notification is triggered because some data was changed on a different device and it is downloaded from CloudKit, or it is triggered from the current device because new entity was saved into database.
Because this notification is posted when both remote data is downloaded or local data is created. It would be great if there is a way to understand the origin of the notification.
CoreData: Zone metadata is missing it's encoded share data but is marked for a mutation: <CKRecordZoneID: 0x600003f044e0; zoneName=com.apple.coredata.cloudkit.share.30BE5FAE-3FE0-4142-90C4-E78FFA90B2A2, ownerName=defaultOwner> - <decode: bad range for [%@] got [offs:312 len:1242 within:0]>
I deployed Xcode to iPhone, emulator and iPhone, and iCloud data is synchronized. But I am using testlight for distribution, so I cannot synchronize. I did not respond in iCloud Kit Database developer mode, and now I have changed to production mode, but there is no response, so I cannot synchronize. That's why.
A few months back, I launched an app that operated solely on a local level. Recently, I've begun the process of integrating it with CloudKit, and so far, the model integration has been successful. I've utilized SwiftData for this task, making it relatively straightforward to adjust the models, as shown below:
`
@Relationship(deleteRule: .cascade, inverse: \ItemForCategory.category)
var itemForCategory : [ItemForCategory]? = [ItemForCategory]()
`
In my initial version of the code, the widget functioned perfectly. However, I've encountered an error recently stating Missing return in instance method expected to return 'ItemForCategory?'.
@MainActor
private func getLastItem () -> ItemForCategory? {
guard let modelContainer = try? ModelContainer(for: Category.self) else {
return nil
}
let descriptor = FetchDescriptor<Category>()
let appCategories = try? modelContainer.mainContext.fetch(descriptor)
let lastItem = appCategories?.compactMap { $0.itemForCategory }.last
return lastItem
}
The error surfaces at the return line of code. I'm hopeful that someone can assist me in resolving this issue. Thank you very much.
I am new to swift. This is my Item.swift.
import SwiftData
@Model
final class Item: Codable {
var id: String
var soundId: String
var soundAppleId: String
var soundType: String
var type: String
var authorId: String
var text: String
var createdAt: Date
var actionsCount: Int
var chainsCount: Int
var rating: Int
var loved: Bool
var replay: Bool
var heartedByUser: Bool
@Relationship var author: Author?
init(id: String, soundId: String, soundAppleId: String, soundType: String, type: String, authorId: String, text: String, createdAt: Date, actionsCount: Int, chainsCount: Int, ratings: Int, loved: Bool, replay: Bool, heartedByUser: Bool, author: Author) {
self.id = id
self.soundId = soundId
self.soundAppleId = soundAppleId
self.soundType = soundType
self.type = type
self.authorId = authorId
self.text = text
self.createdAt = createdAt
self.actionsCount = actionsCount
self.chainsCount = chainsCount
self.rating = ratings
self.loved = loved
self.replay = replay
self.heartedByUser = heartedByUser
self.author = author
}
private enum CodingKeys: String, CodingKey {
case id
case soundId = "sound_id"
case soundAppleId = "sound_apple_id"
case soundType = "sound_type"
case type
case authorId = "author_id"
case text
case createdAt = "created_at"
case actionsCount = "actions_count"
case chainsCount = "chains_count"
case rating
case loved
case replay
case heartedByUser
case author
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
soundId = try container.decode(String.self, forKey: .soundId)
soundAppleId = try container.decode(String.self, forKey: .soundAppleId)
soundType = try container.decode(String.self, forKey: .soundType)
type = try container.decode(String.self, forKey: .type)
authorId = try container.decode(String.self, forKey: .authorId)
text = try container.decode(String.self, forKey: .text)
let dateString = try container.decode(String.self, forKey: .createdAt)
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
if let date = formatter.date(from: dateString) {
createdAt = date
} else {
throw DecodingError.dataCorruptedError(forKey: .createdAt,
in: container,
debugDescription: "Date string does not match format expected by formatter.")
}
actionsCount = try container.decode(Int.self, forKey: .actionsCount)
chainsCount = try container.decode(Int.self, forKey: .chainsCount)
rating = try container.decode(Int.self, forKey: .rating)
loved = try container.decode(Bool.self, forKey: .loved)
replay = try container.decode(Bool.self, forKey: .replay)
heartedByUser = try container.decode(Bool.self, forKey: .heartedByUser)
author = try container.decode(Author.self, forKey: .author)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(soundId, forKey: .soundId)
try container.encode(soundAppleId, forKey: .soundAppleId)
try container.encode(soundType, forKey: .soundType)
try container.encode(type, forKey: .type)
try container.encode(authorId, forKey: .authorId)
try container.encode(text, forKey: .text)
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let dateString = formatter.string(from: createdAt)
try container.encode(dateString, forKey: .createdAt)
try container.encode(actionsCount, forKey: .actionsCount)
try container.encode(chainsCount, forKey: .chainsCount)
try container.encode(rating, forKey: .rating)
try container.encode(loved, forKey: .loved)
try container.encode(replay, forKey: .replay)
try container.encode(heartedByUser, forKey: .heartedByUser)
try container.encode(author, forKey: .author)
}
}
@Model
final class Author: Codable {
var id: String
var image: URL
var username: String
var bio: String?
init(id: String, image: URL, username: String, bio: String?) {
self.id = id
self.image = image
self.username = username
self.bio = bio
}
private enum CodingKeys: String, CodingKey {
case id
case image
case username
case bio
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
image = try container.decode(URL.self, forKey: .image)
username = try container.decode(String.self, forKey: .username)
bio = try container.decodeIfPresent(String.self, forKey: .bio)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(image, forKey: .image)
try container.encode(username, forKey: .username)
try container.encodeIfPresent(bio, forKey: .bio)
}
}
In my ItemView when I try to access something inside author, Swift preview crashes.
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 SwiftData 0x1cb459e90 0x1cb3d3000 + 552592
1 SwiftData 0x1cb45ba7c 0x1cb3d3000 + 559740
2 SwiftData 0x1cb45e5f8 0x1cb3d3000 + 570872
3 SwiftData 0x1cb4190e4 0x1cb3d3000 + 286948
4 audition 0x100b436e0 Item.author.getter + 320 (@__swiftmacro_8audition4ItemC6author18_PersistedPropertyfMa_.swift:9)
5 ContentView.1.preview-thunk.dylib 0x105f23a20 closure #1 in closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 820 (ContentView.swift:89)
6 SwiftUI 0x1cba41308 0x1cb47b000 + 6054664
7 ContentView.1.preview-thunk.dylib 0x105f22ee4 closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 472 (ContentView.swift:84)
8 SwiftUI 0x1cc2e6c40 0x1cb47b000 + 15121472
9 ContentView.1.preview-thunk.dylib 0x105f228b8 closure #1 in closure #1 in ItemCard.__preview__body.getter + 388 (ContentView.swift:83)
...
I have a Category model that's defined like so:
@Model
final class Category {
@Attribute(.unique) var id: UUID
var name: String
var parent_id: UUID? //categories can be children of other categories
init(id: UUID, name: String, parent_id: UUID?) {
self.id = id
self.name = name
self.parent_id = parent_id
}
}
And I'm getting my categories from an API call and putting it into my View:
import SwiftUI
import SwiftData
struct CategoryView: View {
@Environment(\.modelContext) private var modelContext
@Query private var categories: [Category]
@Query(filter: #Predicate<Category>{ $0.parent_id == nil })
private var top_level_categories: [Category]
var spacing: CGFloat = 25
var body: some View {
HStack() {
Text("Categories")
.font(.title.bold())
Spacer()
Text("see all")
}
.padding([.bottom, .top], 0)
VStack(spacing: 20) {
ScrollView(.horizontal) {
HStack(spacing: spacing) {
ForEach(top_level_categories) { category in
Text(category.name!)
}
}
}
}
.onAppear{
getCategories()
}
}
func getCategories() {
get_refresh_token { token in
guard let token = token else {
return
}
var urlRequest = URLRequest (url: URL(string:"https://api.test.com/categories")!)
urlRequest.httpMethod = "GET"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared
.dataTask(with: urlRequest) { (data, response, error) in
do {
if let data = data {
let c = try JSONDecoder().decode([Category].self, from: data)
c.forEach { modelContext.insert($0) }
try? modelContext.save()
}
}
catch {
print(error)
}
}.resume()
}
}
}
This runs fine the first time I run the app but when I run it again, I get the following error:
ForEach<Array<Category>, UUID, Text>: the ID XXXXXX-XXXX-XXXX-XXXX-XXXXXX occurs multiple times within the collection, this will give undefined results!
Not sure why this is happening since I thought putting the @Attribute(.unique) on ID means that the same category won't get added twice?
I'm using CoreData+CloudKit.
It works fine in development, so I deployed to production.
But I cannot see the data in CloudKit DataBase in a testflight version.
I don't know where I missed.
Can I just run in Release mode to check it works?
I am currently writing an app that is about writing stories. As of now, it is fairly simple: ContentView is your "Collection" of stories. PopupView is when you click on a button in ContentView. In popup view you enter the story title. Once you do that, you are brought to a blank page which is StoryView, where the NavigationTitle is what your story title is. Once I finish the story and leave the page / StoryView, it is still there, but once I close the app on my phone and reopen it, the story is gone and is not saved. I am a relatively new developer, so ive been relying on ChatGPT and Google Gemini for the saving parts of this, but it rarely works, and the furthest ive gotten with it is that it saves the story title but doesn't save the content of the story. I have a feeling that the AI is overdoing it as well.
If anyone could help, please do so. Ive been trying to fix this for days. If you need me to provide any code, I am happy to do so.
[Edited by Moderator]
It still didn't work when I signed in again
I know that this has been posted many times, but I am facing an issue where I can't save a model instance. I know that this is due to enums from others trying to find solutions.
The error that shows:
CoreData: error: Row (pk = 2) for entity 'ResidentInfo' is missing mandatory text data for property 'name'
Solutions that I've tried:
removed all enums from their respective structs to being standalone.
making sure all enum calls use the full keyPath
removing CustomStringConvertible from all enums and moving them to rawValue strings
updating Xcode to 15.4b
probably other things I've forgotten at this point
File is too long to fit in post or comments (I'm sorry it's insanely long, it's a complex model), so I'll try to fit what I can where, are there anythings that stand out that may be an issue?
Enums:
enum Gender: String, CaseIterable, Codable {
case male = "Male"
case female = "Female"
case transmale = "Trans Male"
case transfemale = "Trans Female"
case nonbinary = "Nonbinary"
case other = "Other"
}
enum BodyBuild: String, CaseIterable, Codable {
case small = "Small"
case medium = "Medium"
case large = "Large"
}
enum Status: String, Codable {
case incomplete, complete
}
enum HairColor: String, CaseIterable, Codable {
case black = "Black"
case blonde = "Blonde"
case dirtyBlonde = "Dirty Blonde"
case brown = "Brown"
case lightBrown = "Light Brown"
case darkBrown = "Dark Brown"
case red = "Red"
}
enum EyeColor: String, CaseIterable, Codable {
case blue = "Blue"
case brown = "Brown"
case black = "Black"
case green = "Green"
case hazel = "Hazel"
case gray = "Gray"
case heterochromatic = "Heterochromatic"
}
enum RaceEthnicity: String, CaseIterable, Codable {
case native = "American Indian or Alaska Native"
case asian = "Asian"
case black = "Black or African American"
case pi = "Native Hawaiian or Other Pacific Islander"
case white = "White"
case mixed = "2 or More Races/Mixed"
}
enum MarkType: String, CaseIterable, Codable {
case birthMark = "Birth Mark"
case scar = "Scar"
case tattoo = "Tattoo"
case piercing = "Piercing"
case other = "Other"
}
enum heightFormatStyle: String {
case short, long, hash
}
enum suicideRiskLevel: String, Codable {
case low = "Low"
case medium = "Medium"
case high = "High"
}
enum MedicationFrequency: String, CaseIterable, Codable {
case daily = "Daily"
case weekly = "Weekly"
case biweekly = "Bi-Weekly"
case monthly = "Monthly"
case asNeeded = "As Needed"
case temporary = "Temporary Use"
case other = "Other"
}
enum SchoolOption: String, CaseIterable, Codable {
case ged = "GED"
case communityCollege = "Community College"
case university = "4-Year College"
}
enum FamilyDiseaseTypes: String, CaseIterable, Codable {
case alcoholism = "Alcoholism"
case asthma = "Asthma"
case cancer = "Cancer"
case drugAbuse = "Drug Abuse"
case hypertension = "High Blood Pressure"
case nervousBreakdown = "Nervous Breakdown"
case sca = "Sickle Cell Anemia"
case seizures = "Convulsions, Seizures Epilepsy"
case allergies = "Allergies"
case birthDefect = "Birth Defect"
case diabetes = "Diabetes"
case heartDisease = "Heart Disease"
case migraines = "Migraine Headaches"
case obesity = "Obesity"
case tuberculosis = "Tuberculosis"
case thyroid = "Glandular/Thyroid Issues"
}
Structs:
struct IdentifyingInformation: Codable {
var hairColor: HairColor = HairColor.black
var height: Height = Height(feet: 5, inches: 8)
var race: RaceEthnicity = RaceEthnicity.native
var build: BodyBuild = BodyBuild.small
var eyeColor: EyeColor = EyeColor.blue
var hispanic: Bool = false
var distinguishingMarks: [DistinguishingMark] = []
var currentLivingSitutation: String = ""
var currentSupportServices: String = ""
struct DistinguishingMark: Codable, Identifiable {
var id: UUID = UUID()
var type: MarkType = MarkType.tattoo
var location: String = ""
var description: String = ""
var photos: [Data] = []
}
struct Height: Codable {
var feet: Int
var inches: Int
func formatted(formatStyle: HeightFormatStyle = .short) -> String {
switch formatStyle {
case HeightFormatStyle.hash:
return "\(feet)'\(inches)\""
case HeightFormatStyle.long:
return "\(feet) feet \(inches) inches"
case HeightFormatStyle.short:
return "\(feet)ft \(inches)in"
}
}
}
}
struct EmergencyNeeds: Codable {
var food: Bool = false
var shelter: Bool = false
var clothing: Bool = false
var hygeine: Bool = false
var medical: Bool = false
var mentalHealth: Bool = false
var otherNeeds: String = ""
var abuseNeglectAllegations: Bool = false
var abuseReport: AbuseReport? = nil
struct AbuseReport: Codable {
var reportAccepted: Bool = false
var whoAccepted: String = ""
var reportNumber: String = ""
}
}
struct RiskAssessment: Codable {
var selfHarm: Bool = false
var selfHarmAttempt: Bool = false
var selfHarmExplanation: String? = nil
var currentFeelings: String? = nil
var dangerToOthers: Bool = false
var dangerToOthersExplanation: String? = nil
var suicideAssessmentRequired: Bool {
return selfHarm || dangerToOthers
}
}
struct SuicideAssessment: Loopable, Codable {
var dateCompleted: Date = Date()
var familyMember: Bool = false
var treatedMentalIllness: Bool = false
var chronicIllness: Bool = false
var historyOfSelfDestructiveBehavior: Bool = false
var recentLoss: Bool = false
var isolatedAloneHopeless: Bool = false
var goodbyeNoteOrPosessionDelegation: Bool = false
var plan: Bool = false
var betterOff: Bool = false
var wishToDie: Bool = false
var manualReview: Bool = false
var comments: String = ""
var helpCallMade: Bool = false
var riskLevel: suicideRiskLevel {
let riskScore = try? allProperties().reduce(0) { result, property in
if let isTrue = property.value as? Bool, isTrue {
return result + 1
} else {
return result
}
}
switch riskScore! {
case 0 ... 3:
return .low
case 4 ... 7:
return .medium
default:
return .high
}
}
}
[Continued in comments]
Hello.
I recently released a new version (2.6) of my CloudKit syncing CoreData based app.
The new version uses v18 of my data model. V18 is exactly like v17, except for a new optional string field in one of the entities. I diffed the two model versions to be extra sure.
During my test I did not encounter any crash, and I also tested automatic migration, installing 2.55 and building 2.6 on top of it. No troubles.
However my crash logger reports a number of crashes among my users. It's not a huge numbers (10 users over about 900 or more) but I am surprised it crashes at all.
The crash happens when I call NSPersistentCloudKitContainer.loadPersistentStores, I get this error in the completion block:
The model used to open the store is incompatible with the one used to create the store"
I always assumed these slight changes (new field added to an existing model) did not require a manual migration.
Any suggestions?
The deletion is working, but it does not refresh the view. This is similar to a question I asked previously but I started a new test project to try and work this out.
@Model
class Transaction {
var timestamp: Date
var note: String
@Relationship(deleteRule: .cascade) var items: [Item]?
init(timestamp: Date, note: String, items: [Item]? = nil) {
self.timestamp = timestamp
self.note = note
self.items = items
}
func getModifierCount() -> Int {
guard let items = items else { return 0 }
return items.reduce(0, {result, item in
result + (item.modifiers?.count ?? 0)
})
}
}
@Model
class Item {
var timestamp: Date
var note: String
@Relationship(deleteRule: .nullify) var transaction: Transaction?
@Relationship(deleteRule: .noAction) var modifiers: [Modifier]?
init(timestamp: Date, note: String, transaction: Transaction? = nil, modifiers: [Modifier]? = nil) {
self.timestamp = timestamp
self.note = note
self.transaction = transaction
self.modifiers = modifiers
}
}
@Model
class Modifier {
var timestamp: Date
var value: Double
@Relationship(deleteRule: .nullify) var items: [Item]?
init(timestamp: Date, value: Double, items: [Item]? = nil) {
self.timestamp = timestamp
self.value = value
self.items = items
}
}
struct ContentView: View {
@Environment(\.modelContext) private var context
@Query private var items: [Item]
@Query private var transactions: [Transaction]
@Query private var modifiers: [Modifier]
@State private var addItem = false
@State private var addTransaction = false
var body: some View {
NavigationStack {
List {
Section(content: {
ForEach(items) { item in
LabeledText(label: item.timestamp.formatAsString(), value: .int(item.modifiers?.count ?? -1))
}
.onDelete(perform: { indexSet in
withAnimation {
for index in indexSet {
context.delete(items[index])
}
}
})
}, header: {
LabeledView(label: "Items", view: {
Button("", systemImage: "plus", action: {})
})
})
Section(content: {
ForEach(modifiers) { modifier in
LabeledText(label: modifier.timestamp.formatAsString(), value: .currency(modifier.value))
}
.onDelete(perform: { indexSet in
indexSet.forEach { index in
context.delete(modifiers[index])
}
})
}, header: {
LabeledView(label: "Modifiers", view: {
Button("", systemImage: "plus", action: {})
})
})
Section(content: {
ForEach(transactions) { transaction in
LabeledText(label: transaction.note, value: .int(transaction.getModifierCount()))
}
.onDelete(perform: { indexSet in
withAnimation {
for index in indexSet {
context.delete(transactions[index])
}
}
})
}, header: {
LabeledView(label: "Transactions", view: {
Button("", systemImage: "plus", action: {addTransaction.toggle()})
})
})
}
.navigationTitle("Testing")
.sheet(isPresented: $addTransaction, content: {
TransactionEditor()
})
}
}
}
}
Here's the scenario. Create a transaction with 1 item. That item will contain 1 modifier. ContentView will display Items, Modifiers, and Transactions. For Item, it will display the date and how many modifiers it has. Modifier will display the date and its value. Transactions will display a date and how many modifiers are contained inside of its items.
When I delete a modifier, in this case the only one that exist, I should see the count update to 0 for both the Item and the Transaction. This is not happening unless I close the application and reopen it. If I do that, it's updated to 0. I tried to add an ID variable to the view and change it to force a refresh, but it's not updating.
This issue also seems to be only with this many to many relationship. Previously, I only had the Transaction and Item models. Deleting an Item would correctly update Transaction, but that was a one to many relationship.
I would like for Modifier to have a many to many relationship with Items, so they can be reused.
Why is deleting a modifier not updating the items correctly? Why is this not refreshing the view? How can I resolve this issue?
I have a TabView which consists of a few different tabs. One of which does an @Query to retrieve an array of Transaction models. These are then displayed in a list using a ForEach.
struct TransactionsTab: View {
@Query private var transactions: [Transaction]
... other code
Section(content: {
ForEach(transactions) { transaction in
transaction.getListItem()
}
}, header: {
LabeledView(label: "Recent Transactions", view: {
ListButton(mode: .link(destination: {
ListView(list: transactions)
.navigationTitle("All Transactions")
}))
})
})
Transaction contains a different model called TransactionItem and that has a variable called amount. That amount variable is used in the getListItem() function to show how much the total transaction was in the list item.
The issue is that I can delete a Transaction and the ForEach will update to reflect that. However, if I delete an TransactionItem separately, that getListItem() will not show that it's been deleted. The total amount shown will still be as if the TransactionItem was never deleted. It will only update when the app is closed and reopened. Below is the code that's ran when deleting a model, in this case a TransactionItem.
// Deletes a single item
private func delete() {
deleteWarning = false
if let item = itemToDelete {
// If last item is being delete, dismiss the view
if list.count == 1 { dismissView() }
context.delete(item)
context.saveContext()
itemToDelete = nil
}
mode = .view
}
I would think that deleting the model and having it save will cause the transaction query to update. What's going on here to cause it to not update?
By the way, saveContext() just calls the ModelContext save function.
extension ModelContext {
func saveContext() {
do {
try self.save()
} catch {
print("Could not save context: \(error.localizedDescription)")
}
}
}
Many of Apple's tutorials on SwiftData are written alongside SwiftUI, including the sample code.
Would it be a bad idea to use SwiftData separately? If I don't use SwiftUI, would it be wiser to choose a different database instead?
I've been coding for a while after creating the project, but I can't remember clearly if I selected SwiftData initially.
iOS17 using swiftData & CloudKit.
compiles correctly, then throws error "App installation failed: Unable To Install "
Please try again later. Failed to load Info.plist from bundle at path
...
/.../simulatorlocation/.app/Frameworks/SwiftData.framework/Info.plist: No such file or directory.
same error occurs on physical device 15Pro running iOS17.5
how do I fix this?
here is the error:
Please try again later. Failed to load Info.plist from bundle at path /Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework; Extra info about "/Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework/Info.plist": Couldn't stat /Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework/Info.plist:
No such file or directory
Hello. See the code below.
struct ContentView: View {
var body: some View {
TabView {
VehicleTab()
.tabItem({ Label("Vehicles", systemImage: "car.fill")})
.modelContainer(for: Vehicle.self)
TransactionsTab()
.tabItem { Label("Transactions", systemImage: "dollarsign") }
.modelContainer(for: Transaction.self)
}
}
}
Using the .modelContainer() in this way seems to be causing some issue. I was under the assumption that this would just create a container for each view. I get the error below in this configuration. If I comment out either one of the .modelContainer() modifiers, it works fine.
Query encountered an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “default.store” couldn’t be opened."
Are you not able to do what I'm doing? Is there a way to have two separate containers?
We currently have a shoebox-based architecture but want to transition to a document-based architecture, so UIManagedDocument seems like an obvious choice. However, the UIManagedDocument API seems outdated given the relatively newer NSPersistentContainer API. Also, it’s not clear if UIManagedDocument’s managedObjectContext can be used on the main thread or not.
Ideally, I would like to see a persistentContainer property added to UIManagedDocument which could then be used to obtain the view context or a background managed object context.
Does anyone have any suggestions on the latest best practices for document-based architectures using CoreData? I’m more interested in Swift implementations, but knowing best practices for SwiftUI and SwiftData would be helpful too.