Swift - Sort the content of NSSSet - ios

I am using Core Data to fetch the list of clinics, the clinics has relations named doctors mapped to Doctor entity.
My issue is, every time I fetch doctors, which is of type NSSSet, the record is fetched randomly, I want to sort it alphabetically using Doctor.name
I tried the following
self.doctorList = clinic.doctors?.sortedArray(using: [NSSortDescriptor(key: "name", ascending: true)])
Where am I going wrong?
Thanks.

(NS)Set is an unordered collection type.
To order a Set convert it to an array with the allObjects property and sort the array.
self.doctorList = (clinic.doctors!.allObjects as! [Doctor]).sorted(by: { $0.name < $1.name })
You can even sort the set directly but the result is always an array
self.doctorList = (clinic.doctors as! Set<Doctor>).sorted(by: { $0.name < $1.name })
And if the set is declared as native Set<Doctor> anyway you can omit the type cast.
I recommend to declare the doctors relationship as non-optional. If there is no associated doctor the set is empty. But a clinic without any doctor is very unlikely ;-)

Related

Swift: Backendless sorting relationship objects

I have this Backendless tables: Posts and Comments
Posts has a column comments which is has a one-to-many relationship to Comments table.
I'm try to get the comments in a latestOrder first behavior.
Currently, I have this query:
let query = BackendlessDataQuery()
let queryOptions = QueryOptions()
queryOptions.pageSize = size
queryOptions.related = ["comments", "comments.user", "user", "media"]
query.queryOptions = queryOptions
// Used PostObject since it is already mapped using `mapTableToClass`
backendlessInstance.persistenceService.of(PostObject.ofClass()).find(
query,
response: { backendlessPostsList in
let backendlessPostsListOfOffset = backendlessPostsList.getPage(offset)
guard let postObjects = backendlessPostsListOfOffset.getCurrentPage() as? [PostObject] else {
reject(BackendlessError.InvalidTypeForObject(name: "Post"))
return
}
return postObjects
},
error: { fault in
// TODO Find a way to convert a Fault to ErrorType
print("Server reported an error (1): \(fault)")
}
)
What I'm doing currently to sort Post.comments in the view model is reversing it. Post.comments.reverse().
Is there a way to explicitly sort the comments in Backendless level?
You don't have options when using related, and you should really just use it for to-one relationships, not to-many because of this. It would work ok if you have a one-to-few relationship.
So, you should make a separate request for the comments so you can specify a specific page size and sort order. Note that when you specify the variable to sort by (created) you can also add asc or desc to specify the direction of the sort (so created desc).
You could use the sort function.
let sortedComments = Post.comments.sort { $0.date > $1.date }
Of corse your comments will need a published date field for this to work.

Sort fetch request based on relationship attribute

Let's say I have to entities; Item and LocalizableString. The LocalizableString entity have two attributes; string and locale. The Item entity have a to-many relationship to LocalizableString called localizedTitles. Where there's one string entity per "locale".
Now, in my app I have some context/setting that determines what locale I want to use when showing the UI. So let's say I have a UITableViewController with an NSFetchedResultsController handling the data flow.
My question is: can I sort the Item entities based on the LocalizableString's string property where locale is for example en? And can I do this in the fetch request, not after having fetched all items?
Sure you can do that, but you do not have to fetch any particular locale upfront. Your fetched results controller would just fetch the Item objects, and you can then refer to the correct string as you need it.
One way to implement this is to add a convenience function to the Item class, something like the following
func titleWithLocale(identifier: String) -> String? {
if let title = self.localizedTitles.filter
{ $0.locale == identifier }
.first as? LocalizableString {
return title.string
}
return nil
}
Most likely you will have to tweak this code to conform to the strict typing of Swift, but you get the idea.
If you need to sort by the title string, perhaps you need a different approach. If you know that each Item has a localized title in the respective locale you can fetch the LocalizedTitle entity with a predicate the filters for the locale:
request.predicate = NSPredicate(format: "locale = %#", "en")
Obviously, you can sort by string with the usual sort descriptors. Now, to populate your table, you get to the item by following the relationshp in the other direction.
let title = fetchedResultsController.objectAtIndexPath(indexPath)!
let item = title.item
I ended up doing a fetch request for my LocalizableString entity instead. With a predicate that checks the locale and the inverse relationship:
NSPredicate(format: "locale == %# AND itemName != nil", locale)

I'm having trouble fetching entities from core data based on relationships with predicates

Quick background: I have en ExamEntity, which is linked via a relationship to sections covered in the exam (SectionEntity), which is linked via a relationship to the subsections under each section (SubsectionEntity).
What I'm try to do is fetch the sections and related subsections which will be covered be a selected Exam, and store them in a dictionary which can hold multiple string values per key.
My code starts like this:
var sectionsDictionary = [String:[String]]()
//---Fetch Section Entity
let sectionPredicate = NSPredicate(format: "(exam = %#)", selectedExam)
let sectionsFetchRequest:NSFetchRequest = SectionEntity.MR_requestAllWithPredicate(sectionPredicate)
let fetchedSections:NSArray = SectionEntity.MR_executeFetchRequest(sectionsFetchRequest)
All good here. But then I try and fetch the subsections related to the selected sections and things go wrong.
following Code:
for section in fetchedSections {
let sectionName = section.valueForKey("name") as! String
// //error occurs on the line below
let subsectionPredicate = NSPredicate(format: "(section = %#)", section as! SectionEntity)
let subsectionsFetchRequest:NSFetchRequest = SubsectionEntity.MR_requestAllWithPredicate(subsectionPredicate)
let fetchedSubsections:NSArray = SubsectionEntity.MR_executeFetchRequest(subsectionsFetchRequest)
The error I get is:
Could not cast value of type 'NSManagedObject_SectionEntity_' (0x7fb363e18580) to 'MyApp.SectionEntity' (0x10c9213e0).
The next few lines are supposed to iterate through the fetched results, adding their names as values to the dictionary with section names as keys.
for subsection in fetchedSubsections{
let subsectionName = subsection.valueForKey("name") as! String
sectionsDictionary[sectionName] = [subsectionName]
}
}
thanks in advance.
You're not defining the type of the class for your record
Go to the Project.xcdatamodeld file, and select your SectionEntity
Check if the field Class is like this
If it is then write in the Class field "SectionEntity" and press Enter, it should be like this
Then try again
You need to make sure that the elements of the collection you enumerate are of the correct type.
Presumably, Magical Record will return an NSArray of NSManagedObject items. You need to make sure Swift knows what type section is.
for object in fetchedSections {
let section = object as! SectionEntity
// ...
}
Also, see my answer about the unsuccessful casts to NSManagedObject subclasses.

Realm query to exclude results from relations

I have
class Person: Object {
let friends = List<Person>()
let family = List<Person>()
}
I have person instance, which includes links to some other persons in person.friends list.
And I want to query all other Person objects, not including person.friends and person.
I can make two for in loops to check if the query doesn't contain persons from the list, but it seems like not the best way to do that.
P.S. In CoreData I did it with predicate:
let predicate = NSPredicate(format: "SELF != %# AND NOT SELF IN %#",person, person.friends),
But Realm gives me an error:
Predicate expressions must compare a keypath and another keypath or a
constant value
.
Unfortunately, this predicate is currently unsupported in Realm -- you can follow https://github.com/realm/realm-cocoa/issues/1328 for updates.

Realm: sorting by property in child object

My Show object looks like this:
class Show: RLMObject {
dynamic var venue: Venue?
}
and my Venue object:
class Venue: RLMObject {
dynamic var title = ""
}
I need to be able to sort my Show objects by their Venue object's titles. I tried the following but got an error:
allShowsByLocation = Show.allObjects().sortedResultsUsingProperty("venue.title", ascending: true)
The error is: Invalid sort column', reason: 'Column named '(null)' not found.
Realm doesn't yet support sorting RLMResults by a sub-property. As a work-around, you could query for Venues and return its linking object for each index:
allVenues = Venue.allObjects().sortedResultsUsingProperty("title", ascending: true)
func showAtIndex(index: UInt) -> Show {
return (allVenues[index] as Venue).linkingObjectsOfClass("Show", forProperty: "venue")
}
Or you could simply add a venueTitle property to your Show model which would then allow your query to work:
allShowsByLocation = Show.allObjects().sortedResultsUsingProperty("venueTitle", ascending: true)
You can also subscribe to GitHub issue #1199 to follow our progress on supporting sub-property sorting.
I'm very sad when Realm not support this feature.
I try another solution for this issue and it work well
copy all object in RLMResults to an array
Sort sub property of object in Array using compare

Resources