Avoiding sorting in NSDictionary - sorting

I was using NSDictionary and I observed that the objects in the dictionary are sorted automatically with respect to the keys, so my question is how to avoid this sorting, any flag available to set it off, so I get the object in same order I entered.
I know you may be thinking what difference it makes in dictionary since we retrieve the value with respect to key, but I am first getting allKeys from which I receive Array of keys, this order is what I need it to be in the order of how I entered just as in NSArray.

I guess that there will not be a method to control the sorting in NSDictionary, because 'NSDictionary' is a hash table which uses hash function to chose the place to store the values(for speedy accessing).
To customize dictionary you can use CFDictionaryRef there you can write your custom callback. You can write your own CFDictionaryHashCallBack function to compute the place for storing. CFDictionary is "toll-free bridged" with NSDictionary. RegardsDevara Gudda

Related

How to disable sorting for - allObjects in NSMutableSet?

In my OSX app I have NSMutableSet that contains custom objects. I implemented -isEqual and -hash methods in my custom object classes, so that the set can do comparison the way I want.
However, whenever I insert a new object into my set and then call -allObjects, the array that is returned has the objects in a sorted order.
The order depends on the value of the property that I'm using for comparison of my custom objects in -isEqual method mentioned above.
In my case, I want to preserve the order at which the objects were added to the set.
Does anyone have any clue how to achieve that?
Any kind of help is highly appreciated!
Sets don't have an order, they are specifically designed to be unordered collections. When you call allObjects to get an array, the order you get is not defined so you should not depend on it.
You have 2 basic options here if you want to keep using sets.
Order the array manually once you get it.
Use an NSOrderedSet which maintains order.
In my case, I want to preserve the order at which the objects were added to the set.
Then don't use a set, but an NSArray.
Arrays store their objects in an order, sets do not.

Simplest way to derive from NSArray

How would you approach a problem of deriving new NSArray from existing NSArray by removing certain element from original one? I know of NSMutableArray class, but I'd like to know an approach of least moving parts.
In Deriving arrays section of NSArray documentation, there are methods like arrayByAddingObject: or arrayByAddingObjectsFromArray:. However there are no methods for deriving new arrays by removing certain objects.
You filter arrays to get rid of items.
so:
filteredArrayUsingPredicate:
seems to fit your needs. You'll need to provide a predicate, which can be anything you want it to be.
how about the next to method listed: –filteredArrayUsingPredicate: –subarrayWithRange:?
–filteredArrayUsingPredicate: will return a new array with objetcs matching the criteria defind by the predicate.
–subarrayWithRange: will give you a subarray for a certain range
You can create new array using filteredArrayUsingPredicate: method based on your criteria.
Also you can get NSIndexSet containing indexes of objects you want to keep using indexesOfObjectsPassingTest: method and then create new array from original using objectsAtIndexes: method.

Index of item within NSCollectionView

In my collection view I need to generate an index for each item. As Items get reordered I need this index to update with its new position.
The data are Core Data entities in a managed NSArrayController.
The closest I have come to a possible solution is implementing this method on the entity class and then using representedObject.dynamicIndex to bind it to the UI.
- (NSNumber *) dynamicIndex
{
NSInteger r = [[[[self managedObjectContext] registeredObjects] allObjects] indexOfObject:self];
NSNumber *result = [NSNumber numberWithInt:r];
return result;
}
This solution is sketchy at best, and not really functional as it doesn't necessarily reflect the order in the collection view.
Anyone have a model / mechanism for generating or retrieving item indexes in an NSCollectionView?
First, make sure you understand the difference between (and properly use the terminology of) "entity" and "instance." It makes all the difference in communicating your problems/solutions with others.
Second: Don't worry about NSCollectionViewItems ... worry about each one's "represented object," which is held in some container.
Third: Did you want the display order to be a persistent attribute of your entity or do you just need to know what position the item is in at the moment, regardless of what it might be later? Important question.
Fourth: Core Data does not give you the concept of ordered collections. This is to support store types such as NSSQLiteStoreType, where you might only want to fault in a few items (or one) without loading the whole list. Therefore, you're on your own if you want a persistent sort order. To do this, just add an attribute to your entity called "sortOrder" and make it a number type.
Fifth: Because of the "no ordered collections" issue above, your attempt to find the index of a given instance of your entity from an array, built from a set, which was faulted in with a nondeterministic order is doomed to failure.
Sixth: Since you're using an array controller, you'll need to set its sort descriptors. You'll want to use your "sortOrder" key. That way, your fetched instances will always be kept sorted by their "sortOrder."
Seventh and finally: If you're trying to get the index of any objects in your array controller's set/array of objects, you'll want to ask it for its -arrangedObjects, so you're getting the index of the object in the sorted collection the array controller controls.
Hope that helps.
Update for Lion (10.7)
With regard to my sixth point: If you're targeting 10.7 and above in your application, [NSManagedObject now gives you ordered relationships.][1] Use -mutableOrderedSetValueForKey: and -mutableOrderedSetValueForKey: to set and retrieve NSOrderedSets. Yay!

Cocoa's NSDictionary: why are keys copied?

All objects used as keys in NS(Mutable)Dictionaries must support the NSCopying protocol, and those objects are copied when they're used in the dictionary.
I frequently want to use heavier weight objects as keys, simply to map one object to another. What I really mean when I do that is effectively:
[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];
("When I come back and hand you this same key object instance again, get me that same value out.")
...which is exactly what I end up doing to get around this design sometimes. (Yes, I know about NSMapTable in desktop Cocoa; but e.g. iPhone doesn't support this.)
But what I don't really get is why copying the key is necessary or desirable in the first place. What does it buy the implementation or caller?
The copy ensures that the values used as keys don't change "underhand" while being used as keys. Consider the example of a mutable string:
NSMutableString* key = ...
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject: ... forKey: key];
Let's assume that the dictionary did not copy the key, but instead just retained it. If now, at some later point, the original string is modified, then it is very likely that you are not going to find your stored value in the dictionary again even if you use the very same key object (i.e., the one key points to in the example above).
In order to protect yourself against such a mistake, the dictionary copies all keys.
Note, by the way, that it is simple enough to define -copyWithZone: as just doing return [self retain]. This is allowed and good code if your object is immutable, and the NSCopying contract is specifically designed such that the object returned has to be (sorta, kinda) immutable:
Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.
(from NSCopying Reference)
and
The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.
(from -copyWithZone: Reference)
Even if your objects are not immutable, you might get away with that implementation if you only ever use identity-based equality/hash implementations, i.e., implementations which are not affected in any way by the object's internal state.
If you want to store pointers as keys then you'll need to wrap them in a NSValue object with +valueWithPointer:.
Since iOS 6 if you want to use pointers as keys, you can use the NSMapTable object, see http://nshipster.com/nshashtable-and-nsmaptable/
You can specify whether keys and/or values are stongly or weakly held:
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
valueOptions:NSMapTableWeakMemory];
Another option that could be appropriate sometimes is to use NSCache, which holds keys strongly and is actually thread-safe.

How to find a string in an NSArray?

This feels like such a stupid question, but how can I find a string in an NSArray?
I tried using
[array indexOfObjectIdenticalTo:myString]
but that requires the sting to have the same address.
Does anyone have any tips on how to do this?
You want the indexOfObject: method, which looks for the object by sending each object in the array an isEqual: message.
Peter's answer is correct.
One additional note; if you have tons and tons of strings in the array, -indexOfObject: is going to do a linear search. This may prove to be a performance bottleneck for which you should consider using a different container; an NSSet or NSDictionary, possibly (depending on what the strings mean).
Another gotcha is if the strings are all relatively similar and/or relatively long.
Of course, don't bother optimizing anything until you have used the analysis tools to prove that you have a performance issue.
You can use NSOrderSet as the container, the over view in NSOrderedSet Class Reference is below:
NSOrderedSet and its subclass, NSMutableOrderedSet, declare the programmatic interfaces to an ordered collection of objects.
NSOrderedSet declares the programmatic interface for static sets of distinct objects. You >establish a static set’s entries when it’s created, and thereafter the entries can’t be >modified. NSMutableOrderedSet, on the other hand, declares a programmatic interface for >dynamic sets of distinct objects. A dynamic—or mutable—set allows the addition and deletion >of entries at any time, automatically allocating memory as needed.
You can use ordered sets as an alternative to arrays when the order of elements is important >and performance in testing whether an object is contained in the set is a consideration— >testing for membership of an array is slower than testing for membership of a set.
Visit http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSOrderedSet_Class/Reference/Reference.html
containsObject:
Returns a Boolean value that indicates whether a given object is present in the array.
(BOOL)containsObject:(id)anObject
Parameters
anObject
An object.
Return Value
YES if anObject is present in the array, otherwise NO.
Discussion
This method determines whether anObject is present in the array by sending an isEqual: message to each of the array’s objects (and passing anObject as the parameter to each isEqual: message).
Declared In
NSArray.h

Resources