RS: NSObject members class and isMemberOfClass

  • While attempting to find a way to determine if an object ostensibly
    created as an NSMutableArray really is (I can't change it), I wrote
    this code:

    #import <Cocoa/Cocoa.h>

    @interface foo : NSObject {}
    @end

    @implementation foo
    -(void)awakeFromNib {
    NSArray* arr = [NSArray array];
    NSMutableArray* mut = [NSMutableArray array];
    BOOL test1, test2, test3, test4, test5, test6, test7, test8, test9;
    test1 = ([arr isMemberOfClass:[NSArray class]]);
    test2 = ([mut isMemberOfClass:[NSArray class]]);
    test3 = ([arr isMemberOfClass:[NSMutableArray class]]);
    test4 = ([mut isMemberOfClass:[NSMutableArray class]]);
    test5 = ([mut class] == [NSMutableArray class]);
    test6 = ([mut class] == [arr class]);
    test7 = ([NSArray class] == [NSArray class]);
    test8 = ([NSMutableArray class] == [NSMutableArray class]);
    test9 = ([NSArray class] == [NSMutableArray class]);
    NSString* arrStr = [arr className];
    NSString* mutStr = [mut className];
    int mutCount1 = [mut count];
    [mut addObject:@"foo"];
    int mutCount2 = [mut count];
    } //end awakeFromNib
    @end

    When I run it under debugging with a breakpoint on the right-curly
    line, the values of the variables are:
    test1  NO
    test2  NO
    test3  NO
    test4  NO
    test5  NO
    test6  YES
    test7  YES
    test8  YES
    test9  NO
    arrStr NSCFArray
    mutStr NSCFArray
    mutCount1  0
    mutCount2  1

    which don't make sense to me.

    How are the methods <class> and <isMemberOfClass> supposed to work?
    How can I determine if an object ostensibly created as an
    NSMutableArray really is?
  • OK, well as it says in the docs, NSArray and NSMutableArray are
    actually what is known as a class cluster. They are privately
    subclassed by Cocoa in various ways. e.g. NSCFArray.

    However, this shouldn't matter to you, it is an implementation
    detail. So the question that really matters is why you seem to need
    to know this? If you ask Cocoa to create a mutable array, it will,
    and you don't need to know or care about the actual class.

    Mike.

    On 7 Sep 2007, at 11:51, Roland Silver wrote:

    > While attempting to find a way to determine if an object ostensibly
    > created as an NSMutableArray really is (I can't change it), I wrote
    > this code:
    >
    > #import <Cocoa/Cocoa.h>
    >
    > @interface foo : NSObject {}
    > @end
    >
    > @implementation foo
    > -(void)awakeFromNib {
    > NSArray* arr = [NSArray array];
    > NSMutableArray* mut = [NSMutableArray array];
    > BOOL test1, test2, test3, test4, test5, test6, test7, test8, test9;
    > test1 = ([arr isMemberOfClass:[NSArray class]]);
    > test2 = ([mut isMemberOfClass:[NSArray class]]);
    > test3 = ([arr isMemberOfClass:[NSMutableArray class]]);
    > test4 = ([mut isMemberOfClass:[NSMutableArray class]]);
    > test5 = ([mut class] == [NSMutableArray class]);
    > test6 = ([mut class] == [arr class]);
    > test7 = ([NSArray class] == [NSArray class]);
    > test8 = ([NSMutableArray class] == [NSMutableArray class]);
    > test9 = ([NSArray class] == [NSMutableArray class]);
    > NSString* arrStr = [arr className];
    > NSString* mutStr = [mut className];
    > int mutCount1 = [mut count];
    > [mut addObject:@"foo"];
    > int mutCount2 = [mut count];
    > } //end awakeFromNib
    > @end
    >
    > When I run it under debugging with a breakpoint on the right-curly
    > line, the values of the variables are:
    > test1  NO
    > test2  NO
    > test3  NO
    > test4  NO
    > test5  NO
    > test6  YES
    > test7  YES
    > test8  YES
    > test9  NO
    > arrStr NSCFArray
    > mutStr NSCFArray
    > mutCount1  0
    > mutCount2  1
    >
    > which don't make sense to me.
    >
    > How are the methods <class> and <isMemberOfClass> supposed to work?
    > How can I determine if an object ostensibly created as an
    > NSMutableArray really is?
  • On Sep 7, 2007, at 5:51 AM, Roland Silver wrote:

    > While attempting to find a way to determine if an object ostensibly
    > created as an NSMutableArray really is (I can't change it), I wrote
    > this code:
    ...
    > NSArray* arr = [NSArray array];
    > NSMutableArray* mut = [NSMutableArray array];
    > BOOL test1, test2, test3, test4, test5, test6, test7, test8, test9;
    > test1 = ([arr isMemberOfClass:[NSArray class]]);
    > test2 = ([mut isMemberOfClass:[NSArray class]]);
    > test3 = ([arr isMemberOfClass:[NSMutableArray class]]);
    > test4 = ([mut isMemberOfClass:[NSMutableArray class]]);
    > test5 = ([mut class] == [NSMutableArray class]);
    ...

    I concur with Mike Abdullah's point that explicit tests of class
    membership raise a presumption that something is wrong with the design.

    But why are you using isMemberOfClass: instead of isKindOfClass:?

    — F
  • On 07/09/2007, Mike Abdullah <cocoadev...> wrote:
    > OK, well as it says in the docs, NSArray and NSMutableArray are
    > actually what is known as a class cluster. They are privately
    > subclassed by Cocoa in various ways. e.g. NSCFArray.
    >
    > However, this shouldn't matter to you, it is an implementation
    > detail. So the question that really matters is why you seem to need
    > to know this? If you ask Cocoa to create a mutable array, it will,
    > and you don't need to know or care about the actual class.

    Well, it is slightly semantically broken - you ask for an NSArray and
    you get an immutable instance of something which claims to be a
    subclass of NSMutableArray back.

    There isn't any supported way of determining if an array is mutable or
    not. You probably could do it using undocumented private
    CoreFoundation functions, but you shouldn't really need to. If you
    have an array and you need to modify it, and you're not sure if it's
    mutable or not, make a mutable copy. You might want to do this anyway,
    since the person that handed you the array might not want it to be
    modified underneath them. Or if they do, say that you require a
    mutable array, and assume that it will be mutable.

    -- Finlay
  • On 07/09/2007, at 11:15 PM, Finlay Dobbie wrote:

    > There isn't any supported way of determining if an array is mutable or
    > not. You probably could do it using undocumented private
    > CoreFoundation functions, but you shouldn't really need to.

    There are no private functions in CoreFoundation that you can use.
    For purely academic purposes (not to be used in production code) the
    following will tell you if an array happens to be mutable.

    @interface NSArray (IsMutable)

    - (BOOL)isMutable;

    @end

    @implementation NSArray (IsMutable)

    - (BOOL)isMutable
    {
      return ((unsigned short *)self)[2] & 3 ? YES : NO;
    }

    @end

    - Chris
  • On Sep 7, 2007, at 7:15 AM, Finlay Dobbie wrote:

    > There isn't any supported way of determining if an array is mutable or
    > not.

    Actually, there is. Calling -classForCoder on an NSArray will return
    [NSArray class], while calling it on an NSMutableArray will return
    [NSMutableArray class].

    Nick Zitzmann
    <http://www.chronosnet.com/>
  • On 9/7/07, Nick Zitzmann <nick...> wrote:
    >
    > On Sep 7, 2007, at 7:15 AM, Finlay Dobbie wrote:
    >
    >> There isn't any supported way of determining if an array is mutable or
    >> not.
    >
    > Actually, there is. Calling -classForCoder on an NSArray will return
    > [NSArray class], while calling it on an NSMutableArray will return
    > [NSMutableArray class].

    Note that he said "supported way". Who's to say that the result of
    classForCoder won't change between OS updates?

    --
    Clark S. Cox III
    <clarkcox3...>
  • On 08/09/2007, at 6:07 AM, Nick Zitzmann wrote:

    >
    > On Sep 7, 2007, at 7:15 AM, Finlay Dobbie wrote:
    >
    >> There isn't any supported way of determining if an array is
    >> mutable or
    >> not.
    >
    > Actually, there is. Calling -classForCoder on an NSArray will
    > return [NSArray class], while calling it on an NSMutableArray will
    > return [NSMutableArray class].

    I was actually referring to CoreFoundation which didn't appear to
    have even an undocumented way of determining if the array is mutable
    or not.

    Having said that, I had forgotten about using classForCoder and it
    turns out that it uses an undocumented function:

    Boolean _CFArrayIsMutable (CFArrayRef array)

    I hadn't spotted it because it's not in CF-lite.

    - Chris
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today