Partition a FetchedRC (custom order of cells) - ios

I currently have a Note and Tag Relationship which I am trying to sort a tableView by. I am wanting to use a FetchedRC like my other tableViews but am unsure how I would continue using it and have the correct sorting. I am trying to sort by if the Note contains the Tag as a relationship. How can I use a FetchedRC and get this result? This is my current working code that bypasses the FetchedRC and makes its own customOrder Tag array, I just need it somehow to be sorting on the FetchedRC because I would like the built in updating:
private func fetch() {
let request = Tag.fetchRequest() as NSFetchRequest<Tag>
let primarySortDescriptor = NSSortDescriptor(keyPath: \Tag.notes, ascending: true)
request.sortDescriptors = [primarySortDescriptor]
do {
var fetch = try context.fetch(request)
fetch.partition(by: { !($0.notes?.contains(self.note!))! })
self.customOrder = fetch
}
}

Related

Is it possible to perform NSBatchUpdateRequest with an array of NSManagedObjectID?

Currently, I perform multiple update operations via the following code.
func updateOrders(_ updates : [(objectID: NSManagedObjectID, order: Int64)]) {
if updates.isEmpty {
return
}
let coreDataStack = CoreDataStack.INSTANCE
let backgroundContext = coreDataStack.backgroundContext
backgroundContext.perform {
for update in updates {
let objectID = update.objectID
let order = update.order
let nsPlainNote = try! backgroundContext.existingObject(with: objectID) as! NSPlainNote
nsPlainNote.order = order
}
RepositoryUtils.saveContextIfPossible(backgroundContext)
}
}
Since I would like to
Make the update operations run faster
Avoid delegate of NSFetchedResultController from being notified
I would like to utilise NSBatchUpdateRequest for performing such update operation.
However, I don't find a way, how I can apply array of NSManagedObjectID and array of Int64 value, to NSBatchUpdateRequest.
Given an array of NSManagedObjectID and Int64, is it possible to use NSBatchUpdateRequest to perform updated on CoreData?
You must use NSPredicate to set object id
func updateOrders(_ updates : [(objectID: NSManagedObjectID, order: Int64)]) {
updates.forEach {
let request = NSBatchUpdateRequest(entityName: "NSPlainNote")
request.propertiesToUpdate = ["order": $0.order]
request.predicate = NSPredicate(format: "objectID == %#", $0.objectID)
let result = try? context.execute(request)
}
}
NSBatchUpdateRequest is not suitable for your task since using it makes sense for large amount of records with a common attribute's value so that you can filter all by your criteria and update all fields with your values at once.
The fact is that the NSBatchDeleteRequest is an NSPersistentStoreRequest which operates at the SQL level in the persistent store itself and it doesn't update your in-memory objects after execution thats why it works so fast and Core Data translates your native requests to a SQL ones where you can not use dynamically code to get and insert needed data from dictionary etc. but you can update the current value of a filed e.g.:
let batchRequest = NSBatchUpdateRequest(entityName: "Note")
batchRequest.predicate = predicate
// Increase `order` value
batchRequest.propertiesToUpdate = ["order" : NSExpression(format: "order + 1")]
do {
try context.execute(batchRequest)
}
catch {
fatalError(error.localizedDescription)
}

Sorting NSFetchedResultsController items alphabetically but prioritize specific items in Swift and Coredata

I have a method that will fetch a batch of categories from persistent storage. I have added a sort descriptor that sorts the results alphabetically by name (attribute), which works perfectly. But I have 1 item that I would like to show up on top of the list which is "Uncategorized" and another one that I want to show at the bottom of the list which is "Other category". Can anyone help me on how I can pull this off?
What I've tried so far is add another sort descriptor to sort the items by "priority". Priority is an Int16 attribute in the Categories entity. But that didn't achieve what I wanted.
Here's the code to the method.
private func fetchCategories(predicate: NSPredicate, sortDescriptors: [NSSortDescriptor]) -> NSFetchedResultsController<Category> {
let fetchedResultsController: NSFetchedResultsController<Category>
let fetchRequest: NSFetchRequest<Category> = Category.fetchRequest()
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors
//fetch
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
do {
try fetchedResultsController.performFetch()
return fetchedResultsController
} catch {
debug.log(error.localizedDescription)
}
return fetchedResultsController
}
And here's the code calling that method:
func categories(ofType type: TransactionType) -> NSFetchedResultsController<Category> {
let predicate = NSPredicate(format: "tType == %# || tType == \(TransactionType.none.rawValue)", "\(type.rawValue)")
let nameSort = NSSortDescriptor(key: "name", ascending: true)
let fetchedCategories = fetchCategories(predicate: predicate, sortDescriptors: [nameSort])
return fetchedCategories
}
Update:
The priority + name sort solution did not work for me because I think the alphabetical takes precedence. Here's an example case.
Category name -> Priority
Travel -> 4
Food -> 3
Other category -> 255
Entertainment -> 1
Uncategorized -> 0
Expected result
Uncategorized
Entertainment
Food
Travel
Other category
Actual result
Entertainment
Food
Other category
Travel
Uncategorized
So basically, I wanted the ordering that's shown in the expected results above. Where Uncategorized, having a priority of 0 will be shown first, and the Other category item is shown last, having a priority of 255. Everything in between should be in alphabetical order.

How to list a Property in realm Swift 3

How to list a property in realm DB like SELECT columnName FROM mytablein SQL?
Here is my try:let person = self.realm.objects(Person.self).filter("age")
You can access a single property (since Realm models are native objects, they have properties, not columns) of all instances of your particular model class stored in Realm using map.
filter, as its name suggests can be used to only work on a subset of all instances of a certain type that all fulfilled the same condition (for example you can use filter to find all people whose age is above 18 by saying: let adults = self.realm.objects(Person.self).filter("age > 18")).
Get the age property of all instances of Person persisted in Realm using map:
let people = self.realm.objects(Person.self)
let ages = people.map{$0.age}
or in one line giving an Array as an output:
let ages = Array(self.realm.objects(Person.self)).map{$0.age}
you can get list of records like this
let realmCities = try! Realm()
lazy var arrDefaultCities: Results<Cities> = { self.realmCities.objects(Cities.self).sorted(byKeyPath: "cityName", ascending: true) }()
func filterCities()
{
let statePredicate = NSPredicate(format: "stateId = %d", objState.stateId)
arrDefaultCities = try! Realm().objects(Cities.self).filter(statePredicate).sorted(byKeyPath: "cityName", ascending: true)
self.filterArrCities.removeAll()
for objCities : Cities in arrDefaultCities{
if objCities.cityName == APP_DELEGATE.currentCity
{
self.objCity = objCities
}
self.filterArrCities.append(objCities.cityName)
}
}

How to make NSSortDescriptor not in alphabetical order?

So I have a simple shopping list. So far the list is being added alphabetically. When I do ascending false, it goes from Z-A and ascending true is from A-Z.
I just want the items to be added based on when they were added. No ordering, no nothing. It just adds to the back of the list.
Here is what I have so far:
func taskFetchRequest() -> NSFetchRequest<NSFetchRequestResult> {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Shopping")
let sortDescriptor = NSSortDescriptor(key: "item", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
To do this, you must add something like a date-added field to your Shopping object. Then you sort on that date-added value.
This is simply because database (including CoreData) tables don't have an intrinsic ordering. (Often the underlying database engine does generate id's that may seem to increment. But you should never rely on these internal values.)
You are sorting based on the name, I assume that's what item is in this line of code
let sortDescriptor = NSSortDescriptor(key: "item", ascending: false)
If you want to sort by something else, add a property called createdDate (or something) which you can initialise in the ManagedObject's awakeFromInsert method, and then you can use that as the sort key:
let sortDescriptor = NSSortDescriptor(key: "createDate", ascending: false)

NSPredicate to use with Transformable property

I have array of strings which I save in Core Data as Transformable. From json I am gettings needed strings like this:
if let mealTimes = dictionary["mealTimes"] as? [String]{
self.mealTimes = mealTimes
}
Now I would like to filter fetch results by strings in mealTime property. I have tried this way:
let predicate = NSPredicate(format: "mealTimes LIKE[cd] '*%#*'", "breakfast")
var breakfastContents = StaticContent.fetchStaticContentsWithPredicate(predicate, inManagedObjectContext: self.coreDataStack.context)
if (breakfastContents.count > 0) {
breakfast = breakfastContents.first!
}
The problem is that result array is empty but I know I have breakfast string in some content. So how can I fix it? I was reading something about saving transformable as NSData so it would need some great trick. I was trying to use LIKE (with and without *) command and CONTAINS.
Extension for StaticContent:
class func fetchStaticContentsWithPredicate(predicate: NSPredicate, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> [StaticContent] {
// Define fetch request/predicate
var fetchRequest = NSFetchRequest(entityName: "StaticContent")
// Assign fetch request properties
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
// Handle results
let fetchedResults = managedObjectContext.executeFetchRequest(fetchRequest, error: nil) as! [StaticContent]
return fetchedResults
}
You should refactor your data model to get rid of the "array of strings". This is not a very sound way to store this type of values.
Instead, consider a relationship with a new entity that captures those strings. Alternatively, device a scheme where you store a string and have a unique character that separates the records (e.g ; or something similar). Then any simple string predicate would work, like this:
NSPredicate(format: "mealtimes contains[cd] %#", "breakfast")

Resources