isKindOfClass, page 57


#1

Hi,

I’m reading the book from the start, even though I have more than a year of Cocoa experience. I suppose it’s good to repeat some topics just to reaffirm everything in my memory.

So, on page 57 I saw something strange. I was certain that you can not distinguish between mutable and nonmutable objects with -isKindOfClass: method. Well, I chcked this code in my project and all of the tests evaluated as positive:

[code] NSMutableString *mutString = [NSMutableString string];
NSString *nomutString = [NSMutableString string];

if ([mutString isKindOfClass:[NSMutableString class]])
NSLog (@“mutString is NSMutableString.”);
if ([mutString isKindOfClass:[NSString class]])
NSLog (@“mutString is NSString.”);

if ([nomutString isKindOfClass:[NSMutableString class]])
NSLog (@“nomutString is NSMutableString.”);
if ([nomutString isKindOfClass:[NSString class]])
NSLog (@“nomutString is NSString.”);
[/code]
It looks as if you can’t test mutability this way. Other than that, the book seems very well written.


#2

I’ll double-check my stuff, but in your code sample, both mutString and nomutString are pointing at instances of mutable strings:

NSMutableString *mutString   = [NSMutableString string];
NSString        *nomutString = [NSMutableString string];

So, I’m not surprised that they behave the same.


#3

Ah, sorry.

I was experimenting with few other classes, like NSArray/NSMutableArray and in the end, as I tried to reverse to Strings as you have in the book I made a mistake with copy/paste.

Still, even when I change the second line to simple NSString I get the same results. Then I made it even more complicated, just to make sure they are not pointing to some placeholder string and again it all behaves the same.

[code] int i = 0;
NSMutableString *mutString = [NSMutableString stringWithFormat:@“Mut: %d”, i];
NSString *nomutString = [NSString stringWithFormat:@“Non: %@”, mutString];

NSLog (@"(%@) - (%@)", mutString, nomutString);

if ([mutString isKindOfClass:[NSMutableString class]])
NSLog (@“mutString is NSMutableString.”);
if ([mutString isKindOfClass:[NSString class]])
NSLog (@“mutString is NSString.”);

if ([nomutString isKindOfClass:[NSMutableString class]])
NSLog (@“nomutString is NSMutableString.”);
if ([nomutString isKindOfClass:[NSString class]])
NSLog (@“nomutString is NSString.”);
[/code]


#4

I would like to know why it is still true when NSString is checked against NSMutableString.


#5

Hi,

Don’t know if anyone is still following this one but it kind of stuck in my head and then I came across this:

Both NSArray and NSMutableArray are implemented from NSCFArray.

Hence IsKindOfClass will return the same.

Also - NSArray respondsToSelector: @selector(addObject:) will return YES

same behaviour for NSSet, NSString and NSDictionary.

It appears that the only way of truly identifying these is to add an object in a @try / @catch block and catch the exception. However, considered opinion is that if your application design depends on this then your probably on the wrong track.

I’ve already told you more than I know so no questions please !

Gareth


#6

Ok, let’s see if I learned anything from my Objective-C training:

  1. NSMutableArray is a subclass of NSArray.
  2. isKindOfClass: checks for membership in the inheritance hierarchy, while isMemberOfClass: tests for direct membership in a class.

Based on those two things, I would think that if someone wanted to distinguish between mutable and non-mutable objects, they would have to use isMemberOfClass: for correct results. Can someone verify my logic…am I on the right track, or way off base?


#7

Hi,

Completely understand your logic and that’s exactly what I thought - but…

These particular classes are implemented as Class Clusters.
See:http://developer.apple.com/mac/library/documentation/General/Conceptual/DevPedia-CocoaCore/ClassCluster.html

So,
[NSString class] is NSString
[NSMutableString class] is NSMutableString

but
[myNSStringInstance class] is NSCFString
[myNSMutableStringInstance class] is also NSCFString

which means that

[myNSStringInstance isMemberOfClass [NSString class] is not true (NSString vs NSCFString)

So you could create another instance and compare them i.e.
[myNSStringInstance isMemberOfClass [myOtherNSStringInstance class] which will sometimes work out

but try the following:

NSString *string1 = @“UTF32.txt”;
NSString *string2 = [NSHomeDirectory() stringByAppendingPathComponent:string1];
NSTextStorage *storage = [[NSTextStorage alloc] initWithString:string2];
NSString *string3 = [storage string];

NSLog(@“Sting1:%@”, [string1 class]);
NSLog(@“Sting2:%@”, [string2 class]);
NSLog(@“Sting3:%@”, [string3 class]);

and you’ll get:

Sting1:NSCFString
Sting2:NSPathStore2
Sting3:NSBigMutableString

Gareth


#8

But isn’t what you just described a different situation than what we’re discussing? It seems like you’re typecasting whatever object is returned from various message expressions into an NSString object, and then sending that object a class message (which I think would then call the description: method for that class)… That’s not the same thing as simply checking the mutability of an object by using the isMemberOfClass: method.


#9

All of the methods listed do return instances of NSString. But, technically, there isn’t such thing as an instance of “NSString.” Some of the foundation objects are implemented by class clusters. NSString is one of those; it is a “public interface” for the NSString family of classes which you do not directly deal with. For our purposes of using NSString, we don’t really care about the under the hood stuff. We want a string, it has some characters, we know what messages we can send to NSString instances and we’re satisfied. It doesn’t matter which one of the “private concrete classes” of the NSString class cluster we get returned to us from a particular method - it walks and talks like the mythical NSString object and we treat it as such.

Note that also, typecasting a variable does not change anything about the object that it points to.

NSArray *a = (NSArray *)[[NSString alloc] init];

The object pointed to by a is still an instance of NSString (or as we know now, one of those private classes that implement all of the methods of this abstract NSString).