Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

grandM

macrumors 68000
Original poster
Oct 14, 2013
1,551
309
Normally Core Data uses a NSSet. If the order matters though one could opt for an NSOrderedSet. I was wondering what would be faster:
- uses NSSet and add an ID to each element. Use NSPredicate to sort them. Adding elements would require altering the ID of some elements.
- use NSOrderedSet. Unsure how an element is inserted at a specific row in Core Data however when the set is ordered.
 
They promise more than they deliver. Here are some of the reasons I have avoided NSOrderedSets in the past:

- Only a single index to sort items on per relationship (what if we wanted entities to be in a multiple lists, dependent on parent entities, and have each list retain it's own order? You'd have to undo all of your Ordered Set Logic)
- With the above point, that index isn't exposed like a property would be, so using it along side something like NSFetchedResultsController is impossible (see here).
- To avoid auto-generation errors (though if you've been using Swift you've undoubtedly ran into auto generation issues already), which is a bane of Xcode's existence.
- Ordered sets are not actually Sets (no inheritance from NSSet), which causes problems for those who don't anticipate that exception.

In pretty much any situation, I'd suggest a NSSet and then use a dedicated property/column or external relationship to a separate table for managing order.
 
Last edited:
They promise more than they deliver. Here are some of the reasons I have avoided NSOrderedSets in the past:

- Only a single index to sort items on per relationship (what if we wanted entities to be in a multiple lists, dependent on parent entities, and have each list retain it's own order? You'd have to undo all of your Ordered Set Logic)
- With the above point, that index isn't exposed like a property would be, so using it along side something like NSFetchedResultsController is impossible (see here).
- To avoid auto-generation errors (though if you've been using Swift you've undoubtedly ran into auto generation issues already), which is a bane of Xcode's existence.
- Ordered sets are not actually Sets (no inheritance from NSSet), which causes problems for those who don't anticipate that exception.

In pretty much any situation, I'd suggest a NSSet and then use a dedicated property/column or external relationship to a separate table for managing order.
Yes I was just converting it to an NSOrderedSet and was running into problems. Problem is I have a many-to-many relationship between A and B. So if I add an id to B that would solve my ranking if I tap on an instance of A. Not sure though if I won't run into problems as an instance of B can be used for several instances of A.

Talking about Core Data. Do you persist the NSSet immediately or do you first perform your logic on a local array?
 
Yes I was just converting it to an NSOrderedSet and was running into problems. Problem is I have a many-to-many relationship between A and B. So if I add an id to B that would solve my ranking if I tap on an instance of A. Not sure though if I won't run into problems as an instance of B can be used for several instances of A.

I would suggest having a mutual table which maintains the order for all of the B objects that are children of their appropriate A objects.

Talking about Core Data. Do you persist the NSSet immediately or do you first perform your logic on a local array?

Avoid saying "persist" in Core Data for a case like this, since it implies that you're writing to your persistent store (like the database). I think the correct word would be "commit", since a Managed Object Context won't be guaranteeing that its commit will save the data - that's not really its responsibility - instead you are guaranteeing that all of the references to that object in the current context are synchronized and pushed up the stack one level. The distinction is important when working with multiple contexts and when understanding how Core Data splits the responsibility among its parts.

In most situations, I hold to commit my changes to a NSSet until I am ready for the data to be seeded back to the rest of the references of that object in the current context. Also: I'll do my best to do as much of the work directly on the entity, rather than indirectly through the relation, which can be funky or awkward code.
 
I would suggest having a mutual table which maintains the order for all of the B objects that are children of their appropriate A objects.



Avoid saying "persist" in Core Data for a case like this, since it implies that you're writing to your persistent store (like the database). I think the correct word would be "commit", since a Managed Object Context won't be guaranteeing that its commit will save the data - that's not really its responsibility - instead you are guaranteeing that all of the references to that object in the current context are synchronized and pushed up the stack one level. The distinction is important when working with multiple contexts and when understanding how Core Data splits the responsibility among its parts.

In most situations, I hold to commit my changes to a NSSet until I am ready for the data to be seeded back to the rest of the references of that object in the current context. Also: I'll do my best to do as much of the work directly on the entity, rather than indirectly through the relation, which can be funky or awkward code.
ok, so I ought to work with a temporary array or something like that and commit it only when needed. I was just doing some tests. I guess if I ought to use the order in Core data I could use a temporary NSMutableOrderedSet. I have to admit I probably will use the NSSet solution, using one or more predicate to sort the data into a temporary array. One of the things bothering me about using the ordered solution is the day you want to use an external DB. In that case some of the logic got lost. One thing is for sure: the @addObject() does not seem to work using the ordered sets. Seems to be the case since 2011 :s
 
I would suggest having a mutual table which maintains the order for all of the B objects that are children of their appropriate A objects.



Avoid saying "persist" in Core Data for a case like this, since it implies that you're writing to your persistent store (like the database). I think the correct word would be "commit", since a Managed Object Context won't be guaranteeing that its commit will save the data - that's not really its responsibility - instead you are guaranteeing that all of the references to that object in the current context are synchronized and pushed up the stack one level. The distinction is important when working with multiple contexts and when understanding how Core Data splits the responsibility among its parts.

In most situations, I hold to commit my changes to a NSSet until I am ready for the data to be seeded back to the rest of the references of that object in the current context. Also: I'll do my best to do as much of the work directly on the entity, rather than indirectly through the relation, which can be funky or awkward code.
Then again is I ought to go ordered sets and would not use the @addObject() it is pretty simple to add elements. I just read this in a book.
Code:
let walks = currentDog.walks!.mutableCopy() as! NSMutableOrderedSet

walks.addObject(walk)
currentDog.walks = walks.copy() as? NSOrderedSet
That addObject can also be insertObject(object, atIndex: ). Would be pretty easy to add elements at the proper place.
 
If you want to use NSOrderedSet, you'll have to write your own setter and getting or modify the broken one that Apple supplies - auto generation of NSManagedObject subclasses hasn't worked for years for me, so it's something I've moved passed complaining about.

IMO, my biggest beef, which is what you hinting at, is that the order is single and not properly exposed. That lack of exposure makes working with it, especially alongside Core Data API's, way harder than it should be, or just flat out impossible.
 
If you want to use NSOrderedSet, you'll have to write your own setter and getting or modify the broken one that Apple supplies - auto generation of NSManagedObject subclasses hasn't worked for years for me, so it's something I've moved passed complaining about.

IMO, my biggest beef, which is what you hinting at, is that the order is single and not properly exposed. That lack of exposure makes working with it, especially alongside Core Data API's, way harder (or plain impossible) than it should be.
So it would be better just to insert an ID and use a NSSet?
 
So it would be better just to insert an ID and use a NSSet?

Oh for sure, I will always advocate that way - There are very few situations in which using a NSOrderedSet would be useful and wouldn't come back to bite you with changes to your model layer (or UI) in the future.
 
Oh for sure, I will always advocate that way - There are very few situations in which using a NSOrderedSet would be useful and wouldn't come back to bite you with changes to your model layer (or UI) in the future.
I'm in doubt about something else now. I had made a Gallery of GalleryItems. This GalleryItem now coincides with a Photo object in my CoreData. Am I correct I could as well work with an array of Photo now? I'm amongst others thinking of the creation of a new Photo object. If I use a GalleryItem I can create it immediately and use a thread to put it into Core Data. If I use the Photo I must create it in CoreData. Would that make the app slower? Do this GalleryItems still serve a purpose now or should I work directly with Photos (being the Core Data object)?
 
If I understand you correctly, you have the following entities: Gallery, GalleryItem, and Photo.

Ideally, I would setup things like:

Entity: Gallery
Properties: Title, Description
Relationships: To-many -> GalleryItem
-
Entity: GalleryItem:
Properties: Order, AddedOn
Relationships: To-one -> Gallery; To-one -> Photo
-
Entity: Photo
Properties: Path, Title, CreatedOn
Relationships: To-Many -> Gallery Items

This is known as the "Toxi" solution (at least when implementing tagging, but the solution it proposes is relevant here). Using this pattern, you are able to use GalleryItem to bridge your two nodes of data (Gallery and Photo).

Bringing us back to the topic this entire thread is about: a benefit of using this pattern over directly setting Photo in a one-to-many relationship with Gallery is the ability to set metadata on the relation (in this case, the order and addedOn properties) independently of the Photo and Gallery entities, but exposed and directly attached to a relevant entity. This method means you can take advantage of lower-level database sorting and higher level classes like FRC when handling data.

When working in a context like Core Data on the iOS or OS X, your connections are most likely limited to a single client, and as long as your entities properly indexed, you won't likely see a performance hit by needing to hop relationships to gather the necessary data. This method is pretty robust and well established, as well as used in a variety of contexts. I suggest looking into peoples' usage with it and other database patterns to familiarize yourself and see others' experiences.
 
Last edited:
If I understand you correctly, you have the following entities: Gallery, GalleryItem, and Photo.

Ideally, I would setup things like:

Entity: Gallery
Properties: Title, Description
Relationships: To-many -> GalleryItem
-
Entity: GalleryItem:
Properties: Order, AddedOn
Relationships: To-one -> Gallery; To-one -> Photo
-
Entity: Photo
Properties: Path, Title, CreatedOn
Relationships: To-Many -> Gallery Items

This is known as the "Toxi" solution (at least when implementing tagging, but the solution it proposes is relevant here). Using this pattern, you are able to use GalleryItem to bridge your two nodes of data (Gallery and Photo).

Bringing us back to the topic this entire thread is about: a benefit of using this pattern over directly setting Photo in a one-to-many relationship with Gallery is the ability to set metadata on the relation (in this case, the order and addedOn properties) independently of the Photo and Gallery entities, but exposed and directly attached to a relevant entity. This method means you can take advantage of lower-level database sorting and higher level classes like FRC when handling data.

When working in a context like Core Data on the iOS or OS X, your connections are most likely limited to a single client, and as long as your entities properly indexed, you won't likely see a performance hit by needing to hop relationships to gather the necessary data. This method is pretty robust and well established, as well as used in a variety of contexts. I suggest looking into peoples' usage with it and other database patterns to familiarize yourself and see others' experiences.
It's close. At the moment A Gallery can have several GalleryItems. A GalleryItem consists of a photo and indeed the order in the Gallery. This GalleryItem was defined as a local Class and not an Entity hence not commited to Core Data. The purpose was to give the user the impression the photos were sorted. In fact they ought to be sorted using the sorted option on CoreData. I changed it to not sorted though hence a NSSet. During one session the photos kept ordered on the View using the order in this local Class. But you're right if I want the photos to keep the same order I ought to activate the ordered option or insert an extra Entity called GalleryItem.

Would you keep the counterpart of the galleryItems too? If I change everything to entities I have the problem that a user could get the impression the app lags. If I use classes for the view and fire a commit at CoreData then the user won't notice the lag? Or is this lag neglectable?
 
In this regard, I can almost completely ensure that you will not experience any sort of lag.

In a standard environment, the chance that you'll hit any sort of performance cap while transversing a relationship using Core Data is none.
 
  • Like
Reactions: grandM
In this regard, I can almost completely ensure that you will not experience any sort of lag.

In a standard environment, the chance that you'll hit any sort of performance cap while transversing a relationship using Core Data is none.
Problem is that I'm also converting images. So I'm inclined to put this conversion in a queue. However I'm reading that this can cause a problem? I was going to put up a queue and convert the images. In the queue I was going to save to core data. Meanwhile I was going to use the GalleryItems (which at the moment are a copy of the photos) and work on the local class to appear in the UI. Hence removing the chance of a lag due to the conversion.

At the moment I have this function. Could this result into a problem? I'm using the same managedObjectContext I'm always using.

Code:
   func addGalleryPhotoToCoreDataFromImage(image: UIImage) {

      

        dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { () -> Void in

          


            // create a thumbnail and a smaller photo

            let thumbnailImage = self.resizeImage(image, targetSize: CGSizeMake(167, 167))

            let screenSize : CGSize = UIScreen.mainScreen().bounds.size

            let bigImage = self.resizeImage(image, targetSize: CGSizeMake(screenSize.width, screenSize.height))

          

            // save thumbnail and photo to CoreData

            let newPhoto = NSEntityDescription.insertNewObjectForEntityForName("Photo", inManagedObjectContext: self.managedObjectContext!) as! Photo

            newPhoto.thumbnail = UIImageJPEGRepresentation(thumbnailImage, 0.1)

            newPhoto.photo = UIImageJPEGRepresentation(bigImage, 0.9)

            self.photoSet!.addObject(newPhoto)

          

            self.saveToCoreData()

            dispatch_async(dispatch_get_main_queue(), { () -> Void in

                self.refreshItemsInGalleryCollectionView()


            })

          


        }

    }
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.