Core Data EXC_BREAKPOINT - swift

Here is the code that I have used throughout my project without any issues:
var results: NSArray = context.executeFetchRequest(request, error: &error)!
Yet it's crashing! Any ideas why??
More code:
//now get old current and revoke that
var context:NSManagedObjectContext = self.appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "DownloadedCharacters")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "isCurrent = %#", true)
var results: NSArray = context.executeFetchRequest(request, error: &error)!
//error check
if results.count == 1 {
//good
let object:NSManagedObject = results[0] as NSManagedObject
object.setValue(false, forKey: "isCurrent")
println("Revoked old current Object, 1")
//update currents
//find the new object in storage based off saved name
let lookupName = cell.cellData?.valueForKey("saveName") as String
var request2 = NSFetchRequest(entityName: "DownloadedCharacters")
request2.returnsObjectsAsFaults = false
request2.predicate = NSPredicate(format: "saveName = %#", lookupName)
var results2:NSArray = context.executeFetchRequest(request2, error: &self.error)!
if results2.count == 1 {
let object = results2.firstObject as NSManagedObject
object.setValue(true, forKey: "isCurrent")
println("Updated new current")
} else {
println("Fatal error in retreving object for Core Data. Count = \(results.count).")
}
//now update the section of the table
tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.Automatic)
}
Very frustrating. Also, AFTER the problematic line, println("Revoked old current Object, 1") IS being called and IS printing to console.......... any help would be much appreciated

Related

how to modify my Core Data attributes of an entity but on all the elements of my database

hello community I am a novice and this is my first question.
how to change all the attributes of an entity and be able to change all my Core Data elements,
because I can only change the first attribute of an entity but not all my data records.
Here in this function I can only change the name
and then I get this following error has the line:
let objectUpdate = test[0] : Thread 1: Fatal error: Index out of range
func updateData() {
var newName = ""
var newPrenom = ""
newName = name.text!
newPrenom = prenom.text!
let managedContext = AppDelegate.viewContext
let fetchRequest : NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Person")
fetchRequest.predicate = NSPredicate(format: "name = %#", newName)
do {
fetchRequest.predicate = NSPredicate(format: "prenom = %#", newPrenom)
let test = try! managedContext.fetch(fetchRequest) as! [NSManagedObject]
let objectUpdate = test[0]
objectUpdate.setValue(newName,forKey: "name")
objectUpdate.setValue(newPrenom, forKey: "prenom")
do {
try managedContext.save()
}
catch {
print(error)
}
} catch {
print(error)
}
}
There are a number of ways we can avoid this error.
Unwrapping optional .first value
Swift's Collection gives us safe way to get first item, simply by accessing the first property on a given collection. It will return an Optional<Element> value so we need to unwrap it first either by using if let of guard let
if let object = test.first {
// do something with object
}
or
guard let object = test.first else { return }
// do something with object
Checking if value at index exists
It's often a good idea to check for a specific index within the indices property before accessing the value behind it.
if test.indices.contains(0) {
let object = test[0]
// do something with object
}
These hints should prevent your code from crashing again.
Other Suggestions
This is not really safe or clean:
var newName = ""
var newPrenom = ""
newName = name.text!
newPrenom = prenom.text!
We can make it much cleaner and most importantly safer by using a guard statement
guard let newName = name.text, let newPrenom = prenom.text else { return }
Two important things happened here:
No more force-unwrapping the optional values of text [which could cause a crash]
The properties are now immutable, meaning we can be sure that what we are saving to the CoreDate is what was retreived at the beginning of the function
Since the line:
let test = try! managedContext.fetch(fetchRequest) as! [NSManagedObject]
is already wrapped in the do-catch clause, you can safely remove forced try! and replace it with try.
let test = try managedContext.fetch(fetchRequest) as! [NSManagedObject]
Let's use types! On this line you create a NSFetchRequest object for some entity named "Person".
let fetchRequest : NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Person")
I am guessing CoreData have generated for you a NSManagedObject subclass, named Person. If this is true, you could rewrite it like this:
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
With the previous tip implemented, we can now get rid of as! [NSManagedObject] from this line:
let test = try managedContext.fetch(fetchRequest) as! [NSManagedObject]
Since the NSFetchRequest object is now nicely typed, we can take advantage of it by rewriting it like this:
let test: [Person] = try managedContext.fetch(fetchRequest)
So we are using proper types now? cool! Lets now improve this:
objectUpdate.setValue(newName,forKey: "name")
objectUpdate.setValue(newPrenom, forKey: "prenom")
by rewriting this and using properties on Person object
objectUpdate.name = newName
objectUpdate.prenom = newPrenom
No need for introducing second level of do-catch clause, since we are already in one!
do {
try managedContext.save()
}
catch {
print(error)
}
you can easily replace it with just the save() call, like this:
try managedContext.save()
Are you sure these predicates are what you want?
fetchRequest.predicate = NSPredicate(format: "name = %#", newName)
fetchRequest.predicate = NSPredicate(format: "prenom = %#", newPrenom)
What I can read from them is that you are fetching Person object where the name is newName and prenom is newPrenom and then you update it with the same exact values? Are you using some kind of identification of users? like id: Int or id: UUID? It would make much more sense to write something like this
let id: Int = // ID of the user you are currently editing
fetchRequest.predicate = NSPredicate(format: "id == \(id)")
if you are not using any id's, you could try storing the initial values of name and prenom
// in cell declaration - set when you configure your cell
var initialName: String?
var initialPrenom: String?
// then in your function:
fetchRequest.predicate = NSPredicate(format: "name = %#", initialName)
fetchRequest.predicate = NSPredicate(format: "prenom = %#", initialPrenom)
But I just noticed you also override you first predicate with the second one. You need to use NSCompoundPredicate
fetchRequest.predicate = NSCompoundPredicate(
type: .and, subpredicates: [
NSPredicate(format: "name = %#", initialName),
NSPredicate(format: "prenom = %#", initialPrenom)
]
)
Suggested version
func updateData() {
guard let newName = name.text, let newPrenom = prenom.text else { return }
let managedContext = AppDelegate.viewContext
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
fetchRequest.predicate = NSCompoundPredicate(
type: .and, subpredicates: [
NSPredicate(format: "name = %#", initialName),
NSPredicate(format: "prenom = %#", initialPrenom)
]
)
do {
let objects: [Person] = try managedContext.fetch(fetchRequest)
guard let object = objects.first else { return }
object.name = newName
object.prenom = newPrenom
try managedContext.save()
} catch {
print(error)
}
}
If the index 0 is out of range, it means that the array is empty. Before accessing it, add
if test.isEmpty{
return //the fetch request didn't return any values
}

swift core data executeFetchRequest always crash with propertiesToGroupBy

i am having a problem with executeFetchRequest when i use propertiesToGroupBy. I need to fetch dates(saved as string) but similar dates should be avoided, so that i get unique date array. below is the code i used
var arrDates: NSArray = NSArray()
let fetchRequestDates = NSFetchRequest(entityName: "Schedule")
fetchRequestDates.propertiesToGroupBy = ["date"]
fetchRequestDates.propertiesToFetch = ["date"]
fetchRequestDates.resultType = .DictionaryResultType
do {
let result = try managedContext.executeFetchRequest(fetchRequestDates)
arrDates = result as NSArray
} catch {
NSLog("Failed to fetch dates: \(error)")
}
the execution doesn't go further
let result = try managedContext.executeFetchRequest(fetchRequestDates)
and causing SIGBART. If I comment
fetchRequestDates.propertiesToGroupBy = ["date"]
it works but will fetch duplicate dates too. what is the work around?

request selected date of coredata in swift

good morning all together,
i would like to request all data of my coredata where the name field is "meyer"
at the moment, i do it like this way, but i think, this is not the best way to do this.
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var lebensmittel = [LM_ITEMS]()
var LM_ITEM:NSManagedObject!
var x :Int = 0
var NumberOfLM :Int = 0
func DatenAbrufen() {
let fetchRequest = NSFetchRequest(entityName: "LM_ITEMS")
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [LM_ITEMS] {
lebensmittel = fetchResults
while x < fetchResults.count {
var TEMP_LM_ITEM = lebensmittel[x]
if TEMP_LM_ITEM.name == "meyer" {
LM_ITEM = lebensmittel[x]
NumberOfLM++
}
x++
}
}
LebensmittelTable.reloadData()
}
Use a predicate with your NSFetchRequest instead of looping:
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
var lebensmittel = [LM_ITEMS]()
func DatenAbrufen() {
var fetchRequest = NSFetchRequest(entityName: "LM_ITEMS")
fetchRequest.predicate = NSPredicate(format: "name = %#", "meyer")
if let fetchResults = managedObjectContext.executeFetchRequest(fetchRequest, error: nil) as? [LM_ITEMS] {
lebensmittel = fetchResults
}
LebensmittelTable.reloadData()
}

Delete core data entry cannot invoke 'deleteObject' with an argument list of '([AnyObject]?)'

When I try to remove a core data entry from my project, I bump into the error
cannot invoke 'deleteObject' with an argument list of '([AnyObject]?)'
I think this basically asking me to cast the object but when I try this, I get the same error. My code is as follows:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDelegate.managedObjectContext
var error:NSError? = nil
let request = NSFetchRequest(entityName: projectEntityName)
let pred = NSPredicate(format: "projectName = %#", projectName)
request.predicate = pred
let objects = context?.executeFetchRequest(request, error: &error)
if let objectList = objects {
for thisProject in objectList {
thisProject.deleteObject(objects)
}
}
appDelegate.saveContext()
Can anyone help with this?
You have your variables mixed up. deleteObject is a method of the NSManagedObjectContext, and you pass the object to be deleted as the parameter:
if let objectList = objects {
for thisProject in objectList {
context!.deleteObject(thisProject)
}
}
Use as.
thisProject.deleteObject(objects as! [type])

Issue: Saving Json data to Core Data

I am trying to learn how to read data from a blog and save it to core data but the save is not working as intended. There are 4 blog entries and I expect to have 4 different entries in core data. Please see the code below and let me know where i went wrong:
let task = session.dataTaskWithURL(url!, completionHandler:{(data , response, error) -> Void in
if (error != nil){
println(error)
}else{
var jsonResult:NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
var managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!
let newBlog = NSEntityDescription.insertNewObjectForEntityForName("BlogDetails",inManagedObjectContext:managedObjectContext) as NSManagedObject
var dateFormater = NSDateFormatter()
dateFormater.dateFormat = "yyyy-MM-dd HH:mm:ss" //"yyyy-MM-dd"
var readRequest = NSFetchRequest(entityName: "BlogDetails")
for var i = 0; i < ((jsonResult["items"] as? NSArray)?.count)!; i++ {
var item = jsonResult["items"]![i] as NSDictionary
var blogAuthorDirectory = item["author"]! as NSDictionary
var blogAuthor = blogAuthorDirectory["displayName"] as NSString
var blogAuthorImageDirectory = blogAuthorDirectory["image"] as NSDictionary
// concatenate String
var blogAuthorImage = blogAuthorImageDirectory["url"] as NSString
var blogAuthorImageUrl = ("https:" + blogAuthorImage)
var title = item["title"] as String
// convert date from String
var publishedDate:NSDate = dateFormater.dateFromString(stringTmp as NSString)!
// read content
var content = item["content"] as? NSString
// Write it to core data
newBlog.setValue(blogAuthorImageUrl, forKey: "image")
newBlog.setValue(blogAuthor, forKey: "author")
newBlog.setValue(title, forKey: "title")
newBlog.setValue(publishedDate, forKey: "publisheddate")
managedObjectContext.save(nil)
var results = managedObjectContext.executeFetchRequest(readRequest, error: nil)
println(results)
}
}
})
task.resume()
following are the entries in result in the last iteration:
1. It only has 3 dictionary counts out of which values in first 2 count has all items as nil. how is that being generated?
2. With every iteration, it overwrites value in last count and doesn't append it.
Thanks for your help.
If you want to append objects to your CoreData, you need to do insertIntoManagedObjectContext before you call the managedContext.save(nil) method.
However, your
let newBlog = NSEntityDescription.insertNewObjectForEntityForName("BlogDetails",inManagedObjectContext:managedObjectContext) as NSManagedObject
is declared outside of your for loop, so probably no new blog created after each iteration.