CoreData object is fetched in the correct order, but nested objects are un-ordered - swift

I have the following code to fetch Person object from CoreData model:
let fr:NSFetchRequest<Person> = Person.fetchRequest()
let sd = NSSortDescriptor(key: "name", ascending: false)
fr.sortDescriptors = [sd]
let persons = try? dataController.context.fetch(fr)
This works fine, and I get an array of [Person] in the right order (by name).
let children = persons[0].children // children set is in random order
However, each person has multiple Child objects. These are fetched automatically with each Person, however, these Child objects are not sorted. They come in random order.
How can I control the order in which these Child objects are fetched?
Edit: I am aware that I can order the nested objects manually after being fetched from CoreData, but I am reluctant to do that since that would not be efficient and would cause faulting on all child objects. I am looking for a way that lets CoreData fetch the child objects in a certain order.

Related

How can I bulk set the value of some results, while limiting how many I update?

In the code below, I like the simplicity of calling
results.setValue, rather than iterating over an array and calling it a bunch of times.
It seems likely that there is some way to do this without iterating over an array, but I guess really my concern is that it appears to be significantly slower to iterate. In my testing, for 500 results, it took just under 3 milliseconds to update them in bulk, vs. 537 milliseconds to iterate.
Seems like there has got to be a built in way to set the value for a subset of the results. Limiting the results by a count doesn't appear to be supported, due to the lazy nature, but I don't see any simple way to update them in bulk. I could order them by a unique field, and get the 500th and then filter I suppose to get a new result set, but seems like there should be a better way to do it.
var results = realm.objects(CloudUpdate.self).filter("status = %#", "queued")
let limitedResults = updates[0..<500]
try! realm.write {
// this works, except it sets all the results to posted
// results.setValue("posted", forKey: "status")
// I'd like to be able to do
// limitedResults.setValue("posted", forKey: "status")
// or something rather than iterate as below
// -- note that limitedResults gets smaller as we set them
// because of the filter on the results.
while limitedResults.count > 0 {
limitedResults[0].setValue("posted", forKey: "status")
}
}
Realm can do that update using key paths of the object, and the performance over large datasets is very good.
The use case is not clear but if you have a dataset and want to update the first X number of objects, this will do it
Given a person class with a name property
class PersonClass: Object {
#Persisted var name = ""
}
and you want to update the first three names to... "Jay"
let peopleResults = realm.objects(PersonClass.self)
let peopleList = RealmSwift.List<PersonClass>()
peopleList.append(objectsIn: peopleResults[0...2]) //see note
try! realm.write {
peopleList.setValue("Jay", forKey: "name")
}
Keep in mind though, as soon as realm objects are manipulated by high level Swift functions, the performance will degrade and more importantly, those objects are no longer lazily loaded - they are all loaded into memory and could potentially overwhelm the device.
One other thing to note is that Realm has no pre-defined ordering so ensure the results have a .sorted(byKeyPath: if you want to update objects by an order.

How to find array value of a data model in a view container of specific row of that array that user typed?

I don't know how to find array value of that particular index which user has typed. I had connected that array to my data model which contain 2 values ?
I have tried .contain value after implementing a new variable of the data model but it hasn't worked
let productsNamess = document.data()["ProductName"] as! String
let quantityGame = document.data()["Quantity"] as! String
// making a new net stock data incoming class
let newClassForProducts = dataModelOutgoing()
newClassForProducts.productName = productsNamess
newClassForProducts.quantity = Int(quantityGame)
// forward data to main dataincoming main class
self.dataIncoming.append(newClassForProducts)
I dont know how to take data out of an array which contains two values in one array.

xcode swift 4 Core Data relation between entities?

i am trying to make relation entity between 2 entities , unfortunately its not working well since i am still new with swift.
for example i have playlist table and songs table i want to make relation between them ?
and this is the Fetch Request :
let fetchRequest = NSFetchRequest(entityName: "Playlist")
// // Add Sort Descriptor
// let sortDescriptor = NSSortDescriptor(key: "playlist_name", ascending: true)
// fetchRequest.sortDescriptors = [sortDescriptor]
let context = Appdelegate().managedObjectContext
// Execute Fetch Request
do {
let result = try context.executeFetchRequest(fetchRequest)
print(result)
} catch {
let fetchError = error as NSError
print(fetchError)
}
can i create third table to make relation between songs and playlists like this ?
You need to create the relationship in the Core Data model editor. It's easier to use the model editor if you switch it to table mode using this control at the bottom of the window:
When you do that, the main part of the window will look something like this:
Click the "+" button in the relationships section to add a relationship. Fill in the destination entity and be sure to create an inverse relationship.
You should not create a third table to create the relationship. That's something you do in SQL but not in Core Data in most cases.
You may also want to review the relationships section of Apple's Core Data Programming Guide

CoreData: Trying to sort

I have two entities : EntityA and (<-->>) EntityB
and I am trying to fetch all EntityA sorted by EntityB.displayOrder
let request: NSFetchRequest<EntityA> = EntityA.fetchRequest()
context.perform {
do{
var data = try self.context.fetch(request)
let sort = NSSortDescriptor(key: "displayOrder", ascending: true)
for (index,dat) in data.enumerated() {
let entitiesB = (dat.entitiesB?.sortedArray(using: [sort]))
data[index].entitiesB! = NSSet(array: entitiesB!)
}
self.testListTableVC.testData2 = data
self.testListTableVC.tableView.reloadData()
}
}
}
sort seems to be working, but when setting it back to data it isn't sorted..
You are sorting entitiesB, and then setting the data[index].entitiesB equal to entitiesB casted as an NSSet. If you read about NSSets in the docs, you'll see that they are not sorted lists.
You're essentially doing superfluous work, because you're sorting this array and then casting it as an unsorted NSSet
I don't know how you have your model setup, but it looks like you need this data for your testListTableVC.testData2 property. And it seems like whatever kind of array data is, it has a property called entitiesB which is an NSSet. I would recommend making it so that you can use a Swift Array, which would stay organized.

How to add two items at a specific index in an entity in CoreData in Swift

I am moving rows inside a collectionView, I have no sorting on the data so all new cells are inserted at the end of the table, but when I move a cell I want to specifically select the index where it should be moved inside the entity in core data, this way the collectionView will automatically display the moved cell at the updated row without any additional work, is that possible without creating an additional ID attribute?
The entity is named List and it has two attributes, task_name and task_bool.
var myData:[NSManagedObject] = []
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let newItem: AnyObject = NSEntityDescription.insertNewObjectForEntityForName("List",
inManagedObjectContext:
managedContext)
var deleltedRow = myArray[indexPath.row].valueForKey("task_name") as! String
myData.removeAtIndex(indexPath.row)
newItem.setValue(deleltedRow, forKey: "task_name"); // how would I add atIndex: here??
newItem.setValue(true, forKey: "task_bool"); // how would I add atIndex: here??
Core data maintains an unordered collection of objects. If you want to display those objects in a specific order then you need to sort them, either while fetching or afterwards. That means that the objects need to have some information inside them on which you can sort. You don't have anything currently so you'd need to add an order type attribute and maintain it with appropriate values.
Core Data does not store objects in an ordered manner. If you want to display these objects in a specific order, you will need a property/attribute in your entity which lets you order the list the way you want.
It might be a good idea to add a order attribute to the entity and use that for the ordering.