NSOrderedSet for object pointers only - objective-c

I need to store a bunch of objects in an NSOrderedSet object.
Unfortunately, I don't want the set to perform any sort of equality checking on anything other than the object pointer itself.
It appears as though some objects (such as NSNumber) override isEqual: and perform internal value comparison, which means that two NSNumber instances with the same value (but different object pointers) cannot be stored in the same ordered set.
How can I work around this issue?
It has occurred to me that I could just store the object pointer itself as an NSValue or NSString object (using #"%p") instead.
However this means that I need to wrap all calls to containsObject: and indexOfObject: and create a new NSValue or NSString object every time I want to query the set.
Is there any better way of handling this?

Related

Checking if object exist in object array without looping

I would like to check if my NSMutableArray contains my custom object. But if I understand correct contains functions searches for the same object in array (placed at the same memory point)
if(![objectArray containsObject:objToCheck])
{
[objectArray addObject:objToCheck];
}
I know that objectArray has identical object with identical variable values compared to objToCheck, yet such if always returns false. Is there a way to check this without writing custom loop and comparing objects by their parameters?
Override the [NSObject isEqual:] method (actually it's part of the NSObject protocol) of your custom object and check whatever instance variables make sense to you for an object to be considered equal.
Here's an Apple Cocoa Competency article on the subject.
You might try creating a temporary NSSet from your array and testing against that for membership.

Array from set: why does NSSet use allObjects, while NSOrderedSet uses array?

In Foundation, if I want to convert a set to an NSArray, I can use:
-[NSSet allObjects]
-[NSOrderedSet array]
Why are these different?
Speculation, but:
Because when NSSet was created the only other major collection type was NSArray, which was (and still is, largely) the most common collection type. So a method called "allObjects" would obviously return an NSArray.
When NSOrderedSet was added much more recently, it had to deal with the existence of prior collections - primarily, NSArray and NSSet. So an "allObjects" method would be ambiguous. Ergo it has two methods, -array and -set.
And/or, the -array and -set methods return proxies to what are likely the same or similar classes used internally. So in a functional sense they're a little different - those proxies will see mutations made on the original NSOrderedSet. -allObjects on the other hand does not - it genuinely creates an independent array, since its internal storage is likely a hashtable or similar that isn't readily proxied.
While there are other differences†, .allObjects does not imply a definite ordering, and .array does; and that's exactly what you are getting.
† .array returns a live proxy of the underlying NSOrderedSet, and if the underlying ordered set changes, the proxy will change with it.
Also... The NSArray returned by 'allObjects' is a copy of the values in the set.
But the NSArray returned by 'array' is a proxy of the objects in the set.
Thus if you change the value of any object in the set, you will change the value of the object in the array. A copy of the ordered set is not being made. So the two properties have different names because they do different things.

in NSString, NSNumber type property, which is better: retain or copy? (and how about NSArray?)

if object has property of type NSString or NSNumber, which is better, retain or copy?
I think these objects are immutable, (can not change state of object) so copy is better?
I see the example why copy is better that assign NSMutableString and change it, but there's no NSMutableNumber. Then in the case of NSNumber, I'd better use retain to NSNumber objects?
If copy is better because NSString and NSNumber has small memory usage, how about if property is NSArray type?
NSArray type is also immutable, what about use copy in NSArray properties?
With immutable objects, copy.
For immutable objects like most NSStrings, -copyWithZone: is effectively
-(id) copyWithZone: (NSZone*) zone
{
return [self retain];
}
so the overhead is minimal.
With mutable objects, probably copy but with large mutable objects like strings and large mutable arrays, you need to make a judgement call based on profiling your code. Also, of course, with mutable objects you might want the original because you might want to see the changes in the original.
Why can you be interested in copying an immutable object? Actually, immutable classes could simply return [self retain] inside the copy method. What I usually do:
Assign for UI outlets and in some other specific references where it's important to avoid retain cycle
Simply retain immutable objects
Copy simple mutable object
Deep copy for the container types (mutable arrays, dictionaries etc.)
Of course, the rules above are not absolute, but in general they work.

What is the difference between valueforKey:, objectForKey:, and valueForKeyPath:?

I have 2 questions:
What is the difference between valueForKey: and objectForKey:? Is it that one is for NSDictionarys (objectForKey:) and for others it is valueforKey:, or is it the reverse?
Also what is the difference between valueForKey: and valueForKeyPath:? Has it got something to do with Core Data?
Please help.
valueForKey: is part of the NSKeyValueCoding protocol and is therefore part of the key-value coding framework, which allows you to access class properties by name at runtime. That's how NIBs are loaded, for example — the names of properties associated with connections are loaded and then the values are set directly by name. This contrasts with the way that visual interface design tools often work in other languages, generating lots of hidden statically compiled code.
objectForKey: is defined on dictionaries only, and looks up an object by its key. An NSDictionary is a class that stores connections between values and keys.
So, valueForKey: could be used on an NSDictionary to return meta information about the dictionary, such as the count of objects inside it, the list of all keys, etc. objectForKey: would be used actually to look into the dictionary.
At runtime, the difference is that objectForKey: is a method with a completely opaque implementation. valueForKey: explicitly relies on subsequently calling named getters and setters. The reason for the latter is that you can extend key-value coding to key-value observing, where you ask to be informed every time a particular property on a particular object changes. At runtime that's achieved with a method swizzle, where the original setter is replaced by a new one that calls the previous setter and then sends out the required messages. Because all messages are dispatched dynamically, that's just achieved by modifying tables within the object instance.
So any object that is key-value coding compliant (which just means declaring and implementing your properties in the proper way, which the new-ish #property/#synthesize syntax does automatically) can be observed without the object itself having to implement any code.
There's further Apple stuff that uses key-value coding to achieve various things, including CoreData, but it's not specifically to enable any one other technology.
valueForKeyPath: is like valueForKey: except that it can traverse several objects. So you can have a root object with a bunch of properties, each of those properties is another object with another bunch of properties, etc, and using a key path you can retrieve a value way out at the leaf of that data structure rather than having to iterate through object after object for yourself.
In summary, valueForKey: and valueForKeyPath: provide information about object instances and interact with the dynamic nature of the Objective-C runtime. objectForKey: is a dictionary specific method that does dictionary tasks.
Additions:
An example, coded as I type and assuming that NSDictionary is key-value coding compliant:
NSDictionary *someDictionary;
// create someDictionary, populate it, for example (note: we assume photoOfKeys.jpg
// definitely exists, not a good idea for production code — if it doesn't we'll get
// a nil there and anything after it won't be added to the dictionary as it'll appear
// that we terminated the list):
someDictionary = #{ #"favouriteGarment": #"hat",
#"#allKeys" : [NSImage imageNamed:NSImageNameDotMac],
#(2) : NSArray.new };
NSObject *allKeys;
// we make no assumptions about which type #allKeys will be, but are going to assume
// we can NSLog it, so it needs to be a descendant of NSObject rather than 'id' so as
// to definitely respond to the 'description' message — actually this is just compile
// time semantics, but if someone else reads this code it'll make it obvious to them
// what we were thinking...
// some code to get all of the keys stored in the dictionary and print them out;
// should print an array containing the strings 'favouriteGarment', '#allKeys' and
// the number 2
allKeys = [someDictionary valueForKey:#"#allKeys"];
NSLog(#"%#", allKeys);
// some code to get the object named '#allKeys' from the dictionary; will print
// a description of the image created by loading photoOfKeys.jpg, above
allKeys = [someDictionary objectForKey:#"#allKeys"];
NSLog(#"%#", allKeys);
// `objectForKey is analogous to `objectForKeyedSubscript:`, aka
allKeys = someDictionary[#"#allKeys"];
allKeys is a property of NSDictionary as described here. I've also added a mapping from the NSString allKeys to a photograph of some keys. Whether I use the key-value coding valueForKey: methods or the NSDictionary objectForKey: lookup method dictates whether I read the property of the object instance or whether I send the object instance a message asking it to do its unique job.
objectForKey: is a method on NSDictionary for accessing the object associated with a key. valueForKey: is a method on NSObject for accessing any value associated with any object, through the name of a accessor method, property, and/or instance variable.
valueForKeyPath: can be seen as a shorthand for several calls to valueForKey:. You can think of it as sort of a xpath, if you will.
These two statements will result in the same output:
// Using nested valueForKey:
NSLog(#"%#", [[myObject valueForKey:#"foo"] valueForKey:#"bar"]);
// Can be done with a single valueForKeyPath;
NSLog(#"%#", [myObject valueForKeyPath:#"foo.bar"]);
valueForKey:and valueForKeyPath: are part of KVC (Key Value Coding). Introduction and in-depth documentation can be found here: http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/
valueForKey: and valueAtKeyPath: are methods defined in the NSKeyValueCoding informal protocol, and default implementations for both are provided by the root class NSObject.
objectForKey: is a method on NSDictionary.
valueForKey: takes a key to a property, while valueAtKeyPath: takes a so-called keypath. A keypath is a period-delimeted path to a specific property, like #"relationship.property".

How to insert object already existing objects in NSMutableArray list

I am getting a problem, while inserting an object into the main List.
[editContactList addObject:editcontacts];
[editObject.contactList insertObject:editContactList atIndex:0];//error as mutating method sent to immutable object
[editcontacts release];
If you get that particular error, you don't actually have an NSMutableArray; you have an NSArray. Which is immutable. (Note that simply casting an NSArray to NSMutableArray does nothing, the array itself needs to be an instance of a mutable array, rarely seen with instance variables, especially those made accessible publicly.)
Edit: We're going to need some more information; how are these variables defined, how are they initialized, etc.