Any alternatives to NSDictionary for unique keys AND unique values? - objective-c

I'm in the middle of writing some Cocoa classes to parse ID3 tags from MP3 files. To make them as easy to use as possible, I'm allowing the option to request a tag by the actual ID3 frame id ("TCON", "TPE1", "TALB", etc.) or an equivalent word/phrase ("genre", "artist", "album", etc.)
To store this data, currently I have a reference class which returns an NSDictionary with the frame id's as keys, and word/phrases as objects. As I need to look up definitions in both directions, currently I have a second method which returns the dictionary 'switched round', so the words/phrases are the keys.
My question is whether there is a better way to represent this data. Ideally there would be something similar to NSDictionary, the difference being that both the keys and the values must be unique, and you could look up both an "objectForKey:" and a "keyForObject:"
I could write a class for this myself, but I may lose some of the efficiency from hash tables as described in the NSDictionary documentation... also I'd rather keep the number of classes as low as possible in the overall implementation.
Any ideas? Cheers.

Funny you should ask this...
Quinn Taylor, the author of the CHDataStructures framework just added a CHBidirectionalDictionary to the framework last week. It allows you to find objects by key, and find keys by object. It's basically a wrapper around two mutable dictionaries, so you're guaranteed the same lookup time as with a regular dictionary.
The only caveat is that both the object and key must both conform to the NSCopying protocol.

Related

IndexedDB - Do I need an "id" field?

After reading several tutorials I still have problems understanding IndexedDB completely...
I already build a "playground-app" with it, but I have a question before continuing....
Is it recommended to have a distinct "id" field in the ObjectStores?
What happens if object at index 42 (without id-field) needs to be updated? [From what I know IndexedDB doesn't have an update command.] How would you exchange/update this object in-place without breaking the references to this objects?
When you have a id-field - How to find a unused id-value when you add a new object to an ObjectStore? Is there a clever way to do it?
I couldn't find a discussion about this on SO or somewhere else...
cheers!
Using an id is not required but is recommended because it simplifies writing your program. This advice applies to traditional relational databases (SQL) and indexedDB (NoSQL).
Using a simple integer counter is helpful and recommended, even when you have another property or group of properties (a composite/compound primary key) that uniquely identifies each object in a store.
indexedDB provides a way to generate 'unused' id values. Use the autoincrement flag when calling createObjectStore and setting the key path.
See the MDB documentation to learn more. Specifically, review the section on object store keys.
In regards to the 42 question, you can open a cursor, then advance the cursor by 42, and then retrieve the value, change its properties, and then, if the underlying transaction is in readwrite mode, you can call cursor.update to replace the object at the cursor's position. Using this technique is not recommended primarily because it is not practical and can be confusing. It is preferable to use a simple auto-incremented integer id, especially when you are just learning.
It does not matter what the name of the property that represents the key is, so long as it conforms to normal JavaScript object property naming rules, and you access it consistently.

How to create a sorted NSArray from an NSSet that contains arbitrary objects?

I have an NSSet that contains many different types of objects. Typically it will contain some combination of NSDictionaries, NSStrings, NSArrays, and Classes, i.e. the objective-c "Class" type. I need a way to produce an NSArray containing all of the objects in this NSSet, but is sorted so that it will always be in the same order for any set containing the same objects. To be specific, by "same object" I mean by value, not by address. It doesn't matter how it's sorted, as long as it's consistent.
I haven't found a way to do this so far. I can't find any way of doing an ordered comparison between two arbitrary objects. Does anyone have any suggestions on how to accomplish this?
All objects are derived from NSObject, so you could simply sort by [NSObject description] (reference) which will be a summary of the object contents.
EDIT: As pointed out by #Paul.s in the comment; hash (reference) is the way to go (it will be quicker to compare).

Multiple relationships between the same NSManagedObjects

An Author has multiple Books, both of which are NSManagedObjects modeled as a one-to-many relationship using Core Data. 20% of the time I just need to know how many books an author has written, so I check author.books.
40% of the time I need this data by order of date published, and 40% of the time I need it ordered by title. Multiple classes will want to access these ordered lists.
Question 1
Is it reasonable to add two additional methods to Author : NSManagedObject? Since I need to request them from multiple places, it seems smarter than sorting the NSSet each time in the class making the request. I.e:
#property NSSet *books; //core data generated - just returns the unordered set
- (NSArray *)booksByDate //applies an NSSortDescriptor to self.books, returns an NSArray
- (NSArray *)booksByTitle //applies an NSSortDescriptor to self.books, returns an NSArray
Question 2
Using the NSSortDescriptor has proven expensive, with an impact on UI performance. Ideally, I would like to try using the new(ish) NSOrderedSet to model the relationship as ordered, to see if there is a performance benefit. But I can't really pick which way to order the relationship, since whichever I choose (by date or by title) will be non-optimal 40& of the time. Not to mention that I may want to add more sorted variants later.
Is there some way I can have the best of both worlds, and store the relationship 3 times in my Core Data model? Once for the unordered relationship (NSSet), and once each for the ordered relationships (NSOrderedSet). I would only consider this if keeping all three properties in line with each other could be automatic - perhaps by tweaking how the NSManagedObject add/deletes/updates its Books. For example, I would like to somehow customize author.addBook to also insert the same book (in the correct location) into author.booksByDate and author.booksByTitle. And probably hide the
Is something like this possible? Advised? Remember, my main goal is to speed up retrieval of the ordered lists - I am willing to sacrifice write times for inserts/updates/deletes.
I would suggest to try to do the sorting when making the request for the sorted books. If you are presenting this list on a UITableView or a similar interface element, you can use NSFetchedResultsController and its cache system to have your list of sorted books cache. This means that when you try to access the books sorted by dates/titles, the calculation to determine the order of the books is already cached, and your list will be generated faster. I offered a similar solution to a similar question here.

Unique Identifier for NSManagedObject

I have a need to obtain a unique identifier for a type of NSManagedObject I've created. It needs to be available as soon as the object has been created, never change, and be completely unique.
This rules out the NSManagedObjectID, as this can change when the context is saved. I believe the -hash method could be non-unique if my objects have the same properties.
I'd really like to avoid creating an otherwise useless uniqueIdentifier UUID field on the entity as this seems wasteful and messy. Is there an accepted best practice here?
try the URIRepresentation property of NSManagedObjectID. this is very unique ID for the current NSManagerObject but be careful until the NSManagedObject is not saved it gives you a temporary ID only, not a permanent one and they might be different. (I'm just saying it because I don't know for what and how you want to use the unique ID.)
UPDATE #1
this is not an imaginary unique ID only, this is pure unique URL for each individual NSManagedObject (like every file has a unique URL), using them you can find again the original NSManagedObject, after you lost their pointer. I know it is hard to understand, but this is the point of the NSManagedObjectID and its properties.
(if you don't understand how the CoreData and their objects work, you would not downvote the answer. please, read more documentation instead of the pointless downvoting.)
UPDATE #2
according to #NickLocking comment, I would extend the bold part of my answer above:
until saving the NSManagedObjectContext for the the new and still unsaved NSManagedObject classes has a temporary unique ID only. They will get the permanent unique ID after they are saved at first time.
Eventually I have decided that there is no good way to do this, so I just created a uniqueIdentifier field that I apply a UUID to on awakeFromInsert.
Saving the object causes other parts of my application, specifically NSFetchedResultsControllers, to update before I'm finished with the object. I briefly tried NSManagedObjectContext's obtainPermanentObjectIds:withError: method, thinking it would obtain the object IDs without saving the context, but in fact it does simply save the context.
The only unique identifiers provided automatically by CoreData is the object ID, but as you have noted it will change after it is initially created. But before you go coming up with another way to work around this, you might want to consider defining something like the following in your managed object class:
- (NSManagedObjectID *)permID {
if ([[self objectID] isTemporaryID]) {
// Save myself, returning nil if there are errors
}
return [self objectID];
}
This approach isn't perfect by any means, especially if you need to expose the permanent ID before the object is in a state where it is valid and can be saved to the database. But it will allow you to expose a permanent ID in a consistent way as long as you don't need it before the object can be saved.

What is a Dictionary of Arrays in OOP?

In the context of OOP, what is the name (or class name) of a data structure composed of a Dictionary of Arrays?
(a Dictionary where each key is mapped to a collection of values)
In the case you cannot find a class representing this data structure, what would be a proper name for this object?
I came from http://en.wikipedia.org/wiki/List_of_data_structure but the most similar I've found is http://en.wikipedia.org/wiki/Multimap which it seems to me that is wrong because the article talks about cardinality and I don't care about that.
I believe that it is usually just called a Dictionary of Arrays. ;) Usually you don't need a special data structure, you just have a dictionary that has references to Arrays as values.