I have a Core Data model called 'List' with 4 attributes and wanted to populate the data from the JSON file to an array of type 'List'
when I run the app, it gives me the error 'fatal error: Array index out of range'
var loadNames = [List]()
var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
var frc: NSFetchedResultsController = NSFetchedResultsController()
func getFetchedResultsController() -> NSFetchedResultsController {
frc = NSFetchedResultsController(
fetchRequest: listFetchRequest(),
managedObjectContext: context,
sectionNameKeyPath: "done",
cacheName: nil)
return frc
}
func listFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "List")
let doneSortDescriptor = NSSortDescriptor(key: "done", ascending: false)
let nameSortDescriptor = NSSortDescriptor(key: "firstName", ascending: true)
fetchRequest.sortDescriptors = [doneSortDescriptor, nameSortDescriptor]
return fetchRequest
}
func isFrequent(item: List) -> Bool {
return item.frequent == true
}
override func viewWillAppear(animated: Bool) {
var readError:NSError?
let filePath = NSBundle.mainBundle().pathForResource("NameList", ofType:"json")
let data = NSData(contentsOfFile:filePath!, options: NSDataReadingOptions.DataReadingUncached, error:&readError)
var jData = NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers, error: &readError) as! NSArray
for i in 0..<jData.count {
if let jfName = jData[i]["firstName"] as? String {
if let jlName = jData[i]["lastName"] as? String {
if let jDone = jData[i]["done"] as? NSNumber {
if let jFrequent = jData[i]["frequent"] as? NSNumber {
loadNames[i].firstName = jfName //This is where the error is pointing.
loadNames[i].lastName = jlName
loadNames[i].done = jDone
loadNames[i].frequent = jFrequent
println(loadNames.count)
}
}
}
}
}
}
the variables all seem to be getting the data from the JSON file and the value of 'i' in the 'for' loop when the error is happening is '0'.
I don't know why this is happening.
the array count is returning 6, which is the actual amount of objects in the JSON file.
You should use the loadNames array's append method to add each List object. Trying to access index i >= 0 in a zero length array is what is causing your error.
Related
I am saving some key values to Profile entity. But, I am trying to fetch and returning as dictionary to take as key values to main class.
static func fetchProfile) -> [String: Any]? {
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
let profileFetch = NSFetchRequest<NSFetchRequestResult>(entityName: AccountinfoKeyConstant.Entity_Profile)
var fetchedObjects: [String: Any]?
var entityDescription: NSEntityDescription? = nil
entityDescription = NSEntityDescription.entity(forEntityName: AccountinfoKeyConstant.Entity_Profile, in: context)
profileFetch.entity = entityDescription
do {
let objects = try context.fetch(profileFetch)
print("objects \(objects)")
fetchedObjects = objects as [String: Any]
} catch let error as NSError {
print("Could not fetched. \(error), \(error.userInfo)")
}
return fetchedObjects
}
In above code I am getting the following error:
Cannot convert value of type '[Any]' to type '[String : Any]' in coercion
for this line fetchedObjects = objects as [String: Any]
Any suggestions? How to take only dictionary to return it into main class?
Output is:
objects [<Profile: 0x6000026c3ca0> (entity: Profile; id: 0x8d815a305b375e8d <x-coredata://F92995FE-578E-48EB-AA07-242ECBBBBFE4/Profile/p20>; data: {
birthdate = "04/22/2020";
email = "example#test.com";
"family_name" = myName;
gender = " ";
"given_name" = myName123;
name = name123;
})]
To get a dictionary you have to specify the generic NSFetchRequest as NSFetchRequest<NSDictionary> and also to add the dictionaryResultType.
Nevertheless fetching objects returns always an non-optional array.
Further making the method throw reduces the code considerably.
static func fetchProfile() -> [[String: Any]] throws {
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
let profileFetch : NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: AccountinfoKeyConstant.Entity_Profile)
profileFetch.resultType = .dictionaryResultType
return try context.fetch(profileFetch) as! [[String:Any]]
}
If there is only one record in the entity return the first item
static func fetchProfile() -> [String: Any] throws {
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
let profileFetch : NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: AccountinfoKeyConstant.Entity_Profile)
profileFetch.resultType = .dictionaryResultType
let result = try context.fetch(profileFetch) as! [[String:Any]]
return result.first ?? [:]
}
I have a many to many relationship in Core Data with posts and tags. Each tag has many posts and each post has many tags. I have a view controller where I want to display, for a particular tag, all of the posts associated with it.
I do this:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest: NSFetchRequest<Tag> = Tag.fetchRequest()
//3
fetchRequest.predicate = NSPredicate(format: "Tag.name == %#", tag.name!)
// let sort = NSSortDescriptor(key: "timeStamp", ascending: true)
// fetchRequest.sortDescriptors = [sort]
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil) as? NSFetchedResultsController<Tag>
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
tag = fetchedResultsController.object(at: IndexPath(item: 0, section: 0))
tag = Tag(context: managedContext)
let posts = tag.posts
My posts object at the bottom is a Set of objects - unordered. I want an array of posts ordered by timestamp that all belong to this particular tag and Im not sure how to create that.
I know usually to sort items by timestamp you would introduce an NSSortDescriptor like I did in step 3 (but is commented out). But I believe this would sort my fetch request (Tag) by the Tag's timestamp. Each tag doesn't have a timestamp and what I really want to sort is the posts associated with that tag. So I don't believe this is the way to do this.
How do I go about this? I think I could just use swift but it feels like there must be a Core Data way to sort related objects by timestamp
Edit: Updated approach with Paulw11's advice:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let tagFetchRequest: NSFetchRequest<Tag> = Tag.fetchRequest()
let postFetchRequest: NSFetchRequest<Post> = Post.fetchRequest()
//3
tagFetchRequest.predicate = NSPredicate(format: "%K == %#", #keyPath(Tag.name), tag.name!)
do {
let results = try managedContext.fetch(tagFetchRequest)
tag = results.first
} catch let error as NSError {
print("Tag Fetch error: \(error) description: \(error.userInfo)")
}
guard let tag = tag else { return }
postFetchRequest.predicate = NSPredicate(format: "%# IN Post.tags", tag)
let sort = NSSortDescriptor(key: "timeStamp", ascending: true)
postFetchRequest.sortDescriptors = [sort]
fetchedResultsController = NSFetchedResultsController(fetchRequest: postFetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
posts = fetchedResultsController.fetchedObjects as! [Post]
firstPostDate = posts.first?.timeStamp as Date?
lastPostDate = posts.last?.timeStamp as Date?
for (i,post) in posts.enumerated() {
let date = post.timeStamp as Date?
let day = date?.days(from: Calendar.current.startOfDay(for: firstPostDate!))
indexMap[day!] = IndexPath(row: i, section: 0)
}
This gives this error message:
2018-11-29 15:36:56.261887-0800 SweatNetOffline[31250:17419187] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unimplemented SQL generation for predicate : (<Tag: 0x60000216b2a0> (entity: Tag; id: 0xc36a752f5b05e34c <x-coredata://F02C5E33-89B9-4814-9D1B-8C74CAEC7DA1/Tag/p79> ; data: {
mostRecentThumbnail = nil;
mostRecentUpdate = "2018-12-07 21:47:44 +0000";
name = test;
posts = (
"0xc36a752f5af9e34e <x-coredata://F02C5E33-89B9-4814-9D1B-8C74CAEC7DA1/Post/p48>"
);
uuid = nil;
}) IN Post.tags)'
Looks like its inserting that entire object into the query string. This seems wrong but maybe I need to format the object differently?
The key was to use request.predicate = NSPredicate(format: "%# IN self.tags", tag)
as opposed to request.predicate = NSPredicate(format: "%# IN Post.tags", tag)
The context of the predicate is the Post so it no longer needs to be accessed I suppose, it is assumed. Self.tags, tags, and SELF.tags all work.
Here is the full code for fetch data.
Here is the code of fetching data from core data. What is the problem here? Please help what is wrong in fetching data
static func getChatMessagesForGroup( groupId : Double) -> [GroupConversationMessage]{
AppDelegate.getAppDelegate().log.debug("\(groupId)")
let managedContext = CoreDataHelper.getNSMangedObjectContext()
var messages = [GroupConversationMessage]()
var conversationObjects = [NSManagedObject]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: GROUP_CONVERSATION_TABLE_NAME)
let predicate = NSPredicate(format: "\(GroupConversationMessage.FLD_GROUP_ID) = %#", argumentArray: [StringUtils.getStringFromDouble(decimalNumber : groupId)])
fetchRequest.predicate = predicate
let sortDescriptor = NSSortDescriptor(key: GroupConversationMessage.FLD_TIME, ascending: true)
var sortDescriptors = [NSSortDescriptor]()
sortDescriptors.append(sortDescriptor)
fetchRequest.sortDescriptors = sortDescriptors
DispatchQueue.main.sync {
do {
let results = try managedContext.fetch(fetchRequest)
conversationObjects = results as! [NSManagedObject]
} catch let error as NSError {
AppDelegate.getAppDelegate().log.error("Could not fetch \(error), \(error.userInfo)")
}
}
for i in 0 ..< conversationObjects.count {
let message = GroupConversationMessage()
message.uniqueID = conversationObjects[i].value(forKey: QuickRideMessageEntity.UNIQUE_ID) as? String
message.id = conversationObjects[i].value(forKey: GroupConversationMessage.FLD_ID) as! Double
message.groupId = conversationObjects[i].value(forKey: GroupConversationMessage.FLD_GROUP_ID) as! Double
message.senderId = conversationObjects[i].value(forKey: GroupConversationMessage.FLD_SENDER_ID) as! Double
message.senderName = conversationObjects[i].value(forKey: GroupConversationMessage.FLD_SENDER_NAME) as? String
message.message = (conversationObjects[i].value(forKey: GroupConversationMessage.FLD_MESSAGE) as! String)
message.time = conversationObjects[i].value(forKey: GroupConversationMessage.FLD_TIME) as! Double
messages.append(message)
}
return messages
}
I am not sure but you are trying to update or save while fetching the data or maybe your collection type might be immutable and you are trying to mutate it.
I am using JSQCoreDataKit(https://github.com/jessesquires/JSQCoreDataKit) to fetch data from Coredata
So when I fetch, it returns result.objects of type AnyObject
How can I convert it into a array of objects so that I can access the properties like id and name.
internal static func GetCountryEntityList(entityname: String, predicate: String)->AnyObject{
let model = CoreDataModel(name: module, bundle: NSBundle(identifier: bundle)!)
let stack = CoreDataStack(model: model)
let privateStack = CoreDataStack(model: model, storeType: NSInMemoryStoreType, options: nil, concurrencyType: .PrivateQueueConcurrencyType)
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
let countryEntity = entity(name: entityname, context: stack.managedObjectContext)
let request = FetchRequest<Country>(entity: countryEntity)
if predicate != ""{
let predicate = NSPredicate(format: predicate)
request.predicate = predicate
}
request.sortDescriptors = [sortDescriptor]
let result = fetch(request: request, inContext: stack.managedObjectContext)
if !result.success {
println("Error = \(result.error)")
}
return result.objects
}
This is the code for getting data from CoreData using JSQCoreData
var countryListNew = [Country]()
countryListNew = CoreDataManager.GetCountryEntityList("Country", predicate: "") as! [Country]
Above is the code in my Controller
This is what result.objects is
This is what countryListNew is
See I am not able to access name or id
Country class
the fetchedresultController does not return my custom nsmanagedObject in prepareForSegue.
When I add a new entry in my tableView (the "+" button that calls "insertNewObject"), the correct name, from my custom object, appears, with the correct text. But when I click on the line to perform the segue, there is a crash, exc breakpoint, I click on continue, and the program continues without adding more information.
The code to cast the nsmanagedObject as a Section class :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
println("idx: \(indexPath) , objet : \(self.fetchedResultsController.objectAtIndexPath(indexPath))") //outputs ""
let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as Section//NSManagedObject
let controller = (segue.destinationViewController as UINavigationController).topViewController as DetailViewController
//controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Section", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 20
let sortDescriptor = NSSortDescriptor(key: "name", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = [sortDescriptor]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
abort()
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil
func insertNewObject(sender: AnyObject) { //this works
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity!
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context) as Section
newManagedObject.name = String("insert")
var error: NSError? = nil
if !context.save(&error) {
abort()
}
}
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
let section = self.fetchedResultsController.objectAtIndexPath(indexPath) as Section
cell.textLabel.text = section.name;//this works
}