How do I sort an array of different classes? - ios

I have two NSManagedObject classes "Person" and "Animal". Both classes have a "name" property. How can I sort them alphabetically into a single array?
class Person: NSManagedObject {
#NSManaged var name:String?
#NSManaged var occupation:String?
}
class Animal: NSManagedObject {
#NSManaged var name:String?
#NSManaged var breed:String?
}
//This array is filled with both people and animal objects from my database
var peopleAndAnimals = [NSManagedObject]()
peopleAndAnimals.sort(//I want to sort alphabetically by name here)

Try this:
peopleAndAnimals.sortInPlace {
if let name1 = $0.valueForKey("name") as? String,
name2 = $1.valueForKey("name") as? String {
return name1 < name2
} else {
return false
}
}

I would look into using NSSortDescriptor, that's how I usually alphabetize arrays. Here's the NSHipster page for it http://nshipster.com/nssortdescriptor/.

Related

Looping through Core Data relationship

In my calendarViewController I'd like to prepare an array containing dates. In my model i have to-may relationship where one medicine can have multiple dates of taking pill. How can i perform a loop through this set to append an array ?
My models:
extension Medicine {
#NSManaged var amount: String?
#NSManaged var endDate: String?
#NSManaged var name: String?
#NSManaged var time: String?
#NSManaged var notificationSet: NSNumber?
#NSManaged var taken: NSOrderedSet?
}
Model Dates
extension Dates {
#NSManaged var date: NSDate?
#NSManaged var takes: Medicine?
}
I'd like to perform loop like this ,but instead these dates i'd like those from CoreData:
var dates = [NSDate(timeIntervalSinceNow: 60*60*24*2), NSDate(timeIntervalSinceNow: 60*60*24*3), NSDate(timeIntervalSinceNow: 60*60*24*5), NSDate(timeIntervalSinceNow: 60*60*24*7)]
func calendar(calendar: CKCalendarView!, configureDateItem dateItem: CKDateItem!, forDate date: NSDate!) {
for dateTaken in dates {
if calendar.date(date, isSameDayAsDate: dateTaken) {
dateItem.backgroundColor = UIColor.redColor()
}
}
}
Fetch your Medicine entity and then create the array like this:
let dates = medicine.taken.map { $0.date }
Not sure about the NSOrderedSet which tends to be buggy so I generally avoid it, but you can try appending as! [NSDate] to make sure you have an proper array of dates.

Usage NSManagedObject model in code

I have a User model class (generated by XCode with Swift):
#objc(User)
class User: NSManagedObject { }
And it's extension:
extension User {
#NSManaged var id: NSNumber?
#NSManaged var firstName: String?
#NSManaged var lastName: String?
#NSManaged var birthYear: NSNumber?
}
I can save/fetch data from CoreData.
But can I use this class for object management without CoreData things? Or i need to create other class/struct for this?
For example, create User object (without ObjectContext), set his attributes and send it as property in some func? Maybe i can create some struct in class User (like struct {var firstNameData, secondNameData,...}) and use it in code?
I updated class:
struct User {
var id: Int!
var firstName: String!
var lastName: String!
var birthYear: UInt?
}
#objc(UserManagedObject)
class UserManagedObject: NSManagedObject {
func toStruct() -> User {
var userData = User()
userData.id = Int(self.id)
userData.firstName = self.firstName
userData.lastName = self.lastName
if let by = self.birthYear {
userData.birthYear = UInt(by)
}
return userData
}
}
Now for object management i use struct User and UserManagedObject for CoreData in/out

Converting NSSet to NSMutableArray

Currently I have a subclass of NSManaged object called Folder with property called item that is of type NSSet.
class Folder: NSManagedObject {
#NSManaged var title: String
#NSManaged var date: NSDate
#NSManaged var item: NSSet
func itemMutableArray() -> NSMutableArray {
var mutableArray: NSMutableArray!
mutableArray = [item.allObjects]
return mutableArray
}
Item class:
class Item: NSManagedObject {
#NSManaged var title: String
#NSManaged var date: NSDate
#NSManaged var completed: Bool
Does anybody have any suggestions with where I am currently going wrong ?
Here is my previous function I was using which now I want to convert my NSSet to an NSMutableArray.
func itemArray() -> [Item] {
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
return item.sortedArrayUsingDescriptors([sortDescriptor]) as! [Item]
}
func itemMutableArray() -> NSMutableArray {
return NSMutableArray(array: (item.allObjects as! [Item]).sorted{ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending } )
}
use Swift types, they are much more versatile
This puts the NSSet into an Array (var is mutable) and sorts it ascending by property date
#NSManaged var title: String
#NSManaged var date: NSDate
#NSManaged var item: NSSet
var sortedItemArray : Array<Item> {
var array = item.allObjects as! [Item]
return sorted(array) {$0.date < $1.date }
}

Appending PFObject to Array - EXC_BAD_ACCESS

I am currently using Swift and Parse and have run into an issue which I haven't been able resolve for the past several hours.
On a button click, I am attempting to add an Employee object to an Event object's eventAttendee's array.
#IBAction func joinEvent(sender: AnyObject) {
var employee = Employee.currentUser()
employee.events.append(event)
employee.saveInBackgroundWithBlock(nil)
event.eventAttendees.append(employee)
event.saveInBackgroundWithBlock(nil)
}
The event is added to the employee events, but the employee is not added to the event attendees list. The function throws a EXC_BAD_ACCESS (code=1, address=0x0) on the append(employee) line, with no other error message.
My event class looks like this:
class VolunteerEvent : PFObject, PFSubclassing {
#NSManaged var eventName: String
#NSManaged var dateOfEvent: NSDate
#NSManaged var eventDescription: String
#NSManaged var eventURL: String?
#NSManaged var eventImage: PFFile
#NSManaged var contactEmail: String
#NSManaged var contactPhone: NSNumber
#NSManaged var eventOrganizer: Employee
#NSManaged var eventAttendees: [Employee]
class func parseClassName() -> String {
return "VolunteerEvent"
}
}
My Employee class extends PFUser, although when I print out the description of my employee I get that it is a PFUser. I can't tell if this is the issue. When I print out the event, it looks like I expect it to look. I also tried switching the eventAttendees to be an array of PFUser's instead of Employee's, but that didn't work either.
Any help would be much appreciated. Thank you.
I subclass my PFObjects this way,
class Person : PFObject, PFSubclassing {
var firstName: String {
get {
return objectForKey("firstName") as? String ?? ""
}
set {
setObject(newValue, forKey: "firstName")
}
}
}
This way if there is no string in the parse database, I don't get nil, i get an empty string.
You can do this with your array, in fact all your object properties.
If nothing is returned, then you will get an empty array of Employee, rather than a nil object - which will cause your crash when you try an append to it.
You need to initialize your array before adding to it. Try var eventAttendees: [Employee] = []

Many-to-one with primary key (unique constraint)

I've got an Article and a Category model linked by a many-to-one relationship. However, the Category model has a unique constraint on the id property because it's the primary key as you can see below.
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var category: Category()
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
This will work until an Article got the same Category and throw an exception because of the unique constraint.
How am I supposed to implement this kind of relationship ? Is there any built-in way to persist only the Category id and retrieve the corresponding Category ?
Thanks
As you can read in Realm doc (0.92.1), you have to use a List<Object> for a many-to-one relationship.
See this link :
http://realm.io/docs/swift/latest/
class Dog: Object {
dynamic var name = ""
dynamic var owner: Person? // Can be optional
}
class Person: Object {
... // other property declarations
let dogs = List<Dog>()
}
let someDogs = Realm().objects(Dog).filter("name contains 'Fido'")
jim.dogs.extend(someDogs)
jim.dogs.append(rex)
So in your case, I guess it should be something like that :
class Article: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class Category: Object
{
dynamic var id: String = ""
dynamic var title: String = ""
dynamic var articles = List<Article>()
override static func primaryKey() -> String? {
return "id"
}
}
If your Realm version is older :
class Category: Object
{
...
dynamic var categories = RLMArray(objectClassName: Article.className())
}

Resources