Reputation: 1344
I want to store some data downloaded from a remote file in CoreData. his data may already have been downloaded before and then the changes need to be added to core data. I use the code displayed here. In three places I use a Fetchrequest to check if the data is already in the database. I use a predicate with the request. In the code I added comments to distinguish between them. If the item is already in coreData I update the data, else I instantiates a new item. The code to add the item to core data is in a convenience init in the class. This works fine. The problem I am getting is this: The first time in this code id equals 0 so the schoolFetch is performed. Adding the predicate nr 1 gives no error and the school class is instantiated with its id set to 0. Second time id = 1. This means a locationItem, with location being a part of the school, is checked for and instantiated. To add the location to the school a fetchrequest is performed to get the schoolInstance. Predicate 2 is used. This gives no error although the previous added schoolInstance is not retrieved, but it is if the predicate is not used (commented out). After the schoolInstance is retrieved I use a fetchrequest to check if the location is already in coredata. If not it is instantiated, else its data is updated. The predicate nr 3 gives a run-time error stating nothing but EXC_BAD_ACCESS (code=1, address = 0x1). No error description is given in the debugger window. So I have two questions: a) why does predicate nr 2 not return the previous inserted item? b) why does predicate nr 3 give an error?
I structured this code this way as it is possible to first receive the information on the location and after that the information on the school.
if id == 0 {
//get school
let schoolFetch = NSFetchRequest<StreekgidsSchool>(entityName: "School")
schoolFetch.predicate = NSPredicate(format: "locationId == %@", id) // predicate 1
do {
let fetchedSchool = try streekgidsModel?.context.fetch(schoolFetch)
if let school = fetchedSchool?.first{
school.name = name
school.locationId = id
school.colorValue = color
schoolInstance = school
}
else {
//create new entry in coredata for school
schoolInstance = StreekgidsSchool(name: name, context: (streekgidsModel?.context)!)
schoolInstance?.locationId = id
schoolInstance?.colorValue = color
}
} catch {
fatalError("Failed to fetch Schooldata: \(error)")
}
}
else {
//check if school already is defined
let schoolFetch = NSFetchRequest<StreekgidsSchool>(entityName: "School")
schoolFetch.predicate = NSPredicate(format: "locationId == %@", 0) //predicate 2
do {
let fetchedSchool = try streekgidsModel?.context.fetch(schoolFetch)
if let school = fetchedSchool?.first{
schoolInstance = school
}
else {
//create new entry in coredata for school
schoolInstance = StreekgidsSchool(id: 0, context: (streekgidsModel?.context)!)
}
} catch {
fatalError("Failed to fetch Schooldata: \(error)")
}
//get location
let locationFetch = NSFetchRequest<StreekgidsLocation>(entityName: "Location")
locationFetch.predicate = NSPredicate(format: "locationId == %@", id) //predicate 3
do {
let fetchedLocation = try streekgidsModel?.context.fetch(locationFetch)
if let location = fetchedLocation?.first{
location.name = name
location.locationId = id
location.colorValue = color
location.school = schoolInstance
}
else {
//create new entry in coredata for location
let locationInstance = StreekgidsLocation(name: name, context: (streekgidsModel?.context)!)
locationInstance.locationId = id
locationInstance.colorValue = color
}
} catch {
fatalError("Failed to fetch Schooldata: \(error)")
}
}
Upvotes: 2
Views: 1254
Reputation: 4054
Exactly. The %@ is expecting a Foundation object as the argument but an Int is not an object. So your id (set to zero) is being interpreted as nil. That is also why your predicate 2 is returning nothing and why you retrieve the result when you comment it out. Only your third predicate throws a run-time error but in fact all three of your predicates are working incorrectly, the first two are simply not falling over in an immediately visible way. Have you tried substituting %@ for %d.
And as you point out %u for unsigned integers.
Upvotes: 3