Convert NSManaged Object to array iOS Swift - ios

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

Related

How to sort related objects in CoreData?

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.

App getting crashed while fetching data from core data swift

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.

fetching results from core data in one to many relationship

All related questions I saw are in Objective C, but I use Swift.
I have a one to many relationship in core data, one "Current" entity to many "Forecast" entities. I manage to save and get the "Current" entity, but fail to do it for the "matching"for my table "Forecast" entities. The Forecast entities should also be displayed in a UITableView.
This is what I have by now. The array I'm trying to create is always empty. I need some help here:
guard let stack = (UIApplication.shared.delegate as! AppDelegate).stack else {return}
let sortDescriptors = [NSSortDescriptor(key: "city_id_forecast", ascending: true)]
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Forecast")
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.predicate = NSPredicate(format: "main==%#", currentFetched!)
if (currentFetched==nil){
print("current fetched is nil")
}
else{
print("currentFetched is not nil")
}
let fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: stack.context, sectionNameKeyPath: "city_id_forecast", cacheName: nil)
do {try fetchedResultController.performFetch()}
catch {print ("error in performing fetch results\(error)")}
let fetched = fetchedResultController.fetchedObjects
//let fetched = fetchedResultController.
let count = fetched?.count
print ("count of fetched forecast!: \(count!)")
for i in 0..<count!{
let currentFetched = fetched?[i] as? Forecast
let dateForecast = currentFetched?.value(forKeyPath: "date_forecast") as! String
let tempForecast = currentFetched?.value(forKeyPath: "temperature_forecast") as! String
let iconForecast = currentFetched?.value(forKeyPath: "icon_forecast") as! String
let forecastElement = "\(dateForecast), \(tempForecast), \(iconForecast)"
forecastArray.append(forecastElement)

Load data from JSON file to a table

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.

Core Data sort descriptor with NSDate, iOS with Swift

I am trying to filter core data objects depending on a date attribute.
This is my current code:
func getFetchedResultController(selectedEntity: NSString){
let appDelegate : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext: NSManagedObjectContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName(selectedEntity as String, inManagedObjectContext: managedObjectContext)
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 20
let date = NSDate()
let sectionSortDescriptor = NSSortDescriptor(key: "timeStamp < %#",date)
let sortDescriptors = [sectionSortDescriptor] //, secondSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
aFetchedResultsController.delegate = self
self.fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !self.fetchedResultsController.performFetch(&error) {
abort()
}
print(fetchedResultsController.fetchedObjects?.count ?? 0)
}
But I get an error at line:
let sectionSortDescriptor = NSSortDescriptor(key: "timeStamp < %#",date)
How should I change this sort descriptor to get the objects that have an older or a newer date on the "timeStamp" attribute?
Thank you.
To fetch all objects satisfying some condition you don't need a
sort descriptor but a predicate, for example:
let predicate = NSPredicate(format: "timeStamp < %#", date)
fetchRequest.predicate = predicate
You need a sort descriptor to get the objects in a specified order,
for example:
let sectionSortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: true)
let sortDescriptors = [sectionSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
Swift 3.0
This works with no problem for me
let fec:NSFetchRequest = YourEntity.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "type", ascending: true)
fec.sortDescriptors = [sortDescriptor]
let items = try! context.fetch(fec)
>Swift4
func getLastDateFromEntries(entityName:String) -> [NSManagedObject]{
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
let sortDescriptors = NSSortDescriptor(key: "dueDate", ascending: false) // dueDate is key
fetchRequest.sortDescriptors = [sortDescriptors]
fetchRequest.fetchLimit = 1 // add limit
let fetchedResults = try context.fetch(fetchRequest) as! [NSManagedObject]
return fetchedResults
}
catch {
print ("fetch task failed", error)
return []
}
}

Resources