doSomethingWeird


#1

Just a note to the authors, when I was finishing up the Chapter 2 assignments I came across the following difference when performing the “doSomethingWeird” section on Page 57 (2nd Ed). I input the code as written and clicked Build and received the following in the debug area:

2011-08-20 20:14:00.066 RandomPossesions[33358:707] -[NSArrayM doSomethingWeird]: unrecognized selector sent to instance 0x100114880
2011-08-20 20:14:00.087 RandomPossesions[33358:707] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: '-[
NSArrayM doSomethingWeird]: unrecognized selector sent to instance 0x100114880’
*** First throw call stack:

I didn’t copy/paste everything because I think it is unnecessary. What I wanted to point out is that the book states I should be seeing an instance of NSCFArray receiving a message doSomethingWeird. However, the code above shows that NSArrayM is what was sent the message. I’m not sure if this incongruence is because I’m on Xcode 4 or because I may have done something wrong.

It threw an error like the book said it would!


#2

Hmmm…that’s interesting. Using Xcode 4.0.2 on Snow Leopard 10.6.8, I got the msg as described in the book:

2011-08-22 11:24:58.150 RandomPossessions[9872:903] -[NSCFArray doSomethingWeird]: unrecognized selector sent to instance 0x105080
2011-08-22 11:24:58.154 RandomPossessions[9872:903] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: '-[NSCFArray doSomethingWeird]: unrecognized selector sent to instance 0x105080’

The closest I could come to the error you encountered was by doing the array allocation incorrectly:

NSMutableArray * items = [[NSArray alloc] init];

which yielded:

2011-08-22 11:27:36.325 RandomPossessions[9891:903] -[__NSArray0 doSomethingWeird]: unrecognized selector sent to instance 0x1050a0

Can you verify that you used ‘NSMutableArray’ on both sides?


#3

gc3182, I appreciate the post. I can always copy the code/paste the code when I return home tonight though I double and tripled checked it. I noticed that the error in your log was similar yet different, NSArray0 vs NSArrayM. I am running Xcode 4.1 on Lion 10.7.1 which could account for the difference since the book would have been written using Xcode 4.0 on Snow Leopard also.


#4

NSArray and NSMutableArray are class clusters. When you create an instance of one of these classes, a private subclass is used instead. When you log to the console, what you are seeing is one of these private subclasses (_NSArrayM). These are still NSArrays, because they inherit from NSArray, and you can therefore send them the same messages. However, the storage and internal implementations differ depending on their use.

Class clusters are a pretty deep topic, but I can give you the general idea using the example of NSNumber.

If you create an instance of NSNumber ([NSNumber alloc]), instead of allocating a brand new object, you get back an instance of NSNumberPlaceholder. There is only one instance of NSNumberPlaceholder in an application. When you initialize NSNumberPlaceholder,
two things can happen:

  1. If the number is a “common” number, like 0, 1, 2, 3, etc. you are returned a constant instance of NSNumber that represents this value. Thus, if you create two NSNumbers with the value 0, they are actually the same object and you can’t destroy it.

  2. If the number is uncommon, the type of initialization method determines which private subclass of NSNumber to use. For example, if you initialize NSNumberPlaceholder with a double, a special NSNumber subclass for storing a double is instantiated. If you initialize it with an integer, a different subclass is used.

Thus, you don’t have to worry about storage and what is going on underneath the hood: you just think “NSNumber”. The class cluster design pattern is useful because it simplifies the use of NSNumber and it is a pretty good optimization (caching for common numbers, no extra storage for each instance of NSNumber).