Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding non NSObjects to NSMutableArray

This recent SO discussion has confused me. The NSMutableArray prototype for addObject: is

- (void)addObject:(id)anObject

and id is defined in objc.h as

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id; 

When I add an NSObject or subclass to an NSMutableArray, its retain count is incremented, and when I remove it from an NSMutableArray it is decremented. Does this mean that if an id type which is not an NSObject or subclass is added to an NSMutableArray, it has to respond to retain and release messages? The definition of id does not seem to force this. Is it an objective C directive that any id type should respond to standard memory management messages?

like image 766
jbat100 Avatar asked Oct 26 '11 15:10

jbat100


3 Answers

The hard truth about most Foundation containers (and by extent most Apple-developed classes, and by extent also most classes developed by third parties) is that when a method accepts the id type, it should really read id<NSObject>, which means any type that responds to the NSObject protocol. Instances of classes that aren't part of the NSObject hierarchy are unlikely to respond to -retain and -release, which is especially inconvenient when trying to add them to a container. They're also unlikely to respond to -hash, -isEqual:, -description, -copy, and to all the other methods Foundation containers can use on their contents for whatever reason.

For instance, if you attempt to add Class objects to a Foundation container (other than NSMapTable since this one was designed with a lot of flexibility in mind), you'll hit a wall because "modern" ObjC classes are expected to inherit from NSObject, or at least implement the NSObject protocol.

This is a pretty rare situation, though. Class is pretty much the only useful class around that doesn't inherit from NSObject.

like image 133
zneak Avatar answered Oct 21 '22 11:10

zneak


Does this mean that if an id type which is not an NSObject or subclass is added to an NSMutableArray, it has to respond to retain and release messages?

By default, Yes, although there are workarounds to this using CF-APIs.

The definition of id does not seem to force this. Is it an objective C directive that any id type should respond to standard memory management messages?

It's just how the libraries have been written; Root classes (does not inherit from NSObject) are very unusual. An alternative could be - (void)addObject:(id<NSObject>), but that would require a rather large extension to your root class... perhaps a better solution would have been a protocol NSReferenceCounted which takes the relevant bits from NSObject.

However, the NS-collections types really assume that they are dealing with NSObjects (e.g. dictionaries use hash and description).

like image 4
justin Avatar answered Oct 21 '22 12:10

justin


No, there is no convention that objects of type "id" should respond to retain/release messages; in fact, one might say guaranteeing the existence of those kinds of methods is the purpose of the NSObject protocol (not the class). However, "id" does tell the compiler "don't bother type checking", so when you add an object to an nsarray that does not implement those methods, it will compile, but you will get a runtime crash. See http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html for a more detailed explanation.

like image 2
edsko Avatar answered Oct 21 '22 11:10

edsko