Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective C: how to check if variable is NSArray or NSMutableArray

Tags:

How can i check if a variable is an NSArray or an NSMutableArray?

like image 984
Alexander Avatar asked Nov 24 '09 08:11

Alexander


People also ask

What is difference between NSArray and NSMutableArray?

The primary difference between NSArray and NSMutableArray is that a mutable array can be changed/modified after it has been allocated and initialized, whereas an immutable array, NSArray , cannot.

What's a difference between NSArray and NSSet?

The main difference is that NSArray is for an ordered collection and NSSet is for an unordered collection. There are several articles out there that talk about the difference in speed between the two, like this one. If you're iterating through an unordered collection, NSSet is great.

What is NSArray Objective C?

An object representing a static ordered collection, for use instead of an Array constant in cases that require reference semantics.

What is NSMutableArray Objective C?

The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray . NSMutableArray is “toll-free bridged” with its Core Foundation counterpart, CFMutableArray .


2 Answers

*Note that the implementation of NS{,Mutable}Array has changed since this answer was written. As a result, isKindOfClass: now works. On what platforms where and when, I don't know.

Until it is documented as safe to do so, I would strongly recommend NOT writing code that tries to detect whether a collection is mutable or immutable. Even if it were safe, such a design pattern is almost always indicative of a serious design flaw.

(For those with access) Filed rdar://10355515 asking for clarification.


Consider:

int main (int argc, const char * argv[]) {     NSArray *array = [NSArray arrayWithObjects: [NSObject new], nil];     NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects: [NSObject new], nil];      NSLog(@"array's class: %@", NSStringFromClass([array class]));     NSLog(@"mutableArray's class: %@", NSStringFromClass([mutableArray class]));      NSLog(@"array responds to addObject: %@",            [array respondsToSelector: @selector(addObject:)] ? @"YES" : @"NO");      return 0; } 

(I'm using non-empty arrays because an empty NSArray is common enough that Cocoa offers a single shared instance as an optimization.)

array's class: NSCFArray mutableArray's class: NSCFArray array responds to addObject: YES 

I.e. neither -isKindOfClass: nor checking for implementation of addObject: will work.

In short, you can't tell the difference between an NSArray and an NSMutableArray. This is by design and very much the intended behavior. It also holds true for NSString, NSDictionary and NSSet (all of which have a mutable subclass).

That may come as a surprise. The reality, though, is that design patterns that require checking for mutability are confusing to use and incur significant overhead.

For example, if test-for-mutability were a common pattern than all of the methods in Cocoa that return NSArray instances would have to actually return NSArray instances and never return a reference to the internal NSMutableArray that might be being used.

like image 112
bbum Avatar answered Sep 22 '22 06:09

bbum


Bad but technically accurate advice...

The only way to do it is to invoke [unknownArray addObject:someObject] inside a @try/@catch block and catch the NSInternalInconsistencyException that will be thrown if unknownArray is immutable (the actual exception could be a method not implemented or a class is immutable exception).

Good advice...

The short answer though is never try to peer inside an immutable object to see if it is internally mutable.

The reason peering at the mutability of immutable objects is prevented, is to support methods on classes that work like this:

- (NSArray *)internalObjects {     return myInternalObjects; } 

the object myInternalObjects could be mutable but this method on this class is saying: don't mutate what I return to you. There may be serious dangers with doing so. If the class allows you to change the array, it will have a different accessor or mutator method.

If you have a friend class that needs mutable access to the myInternalObjects variable, then declare a special adapter category that only the friend class imports with a method like

- (NSMutableArray *)mutableInternalObjectsArray; 

This will allow the friend (which you are assuming is smart enough to not violate special rules) to have the access it needs but without exposing mutability in a broader sense.

like image 45
Matt Gallagher Avatar answered Sep 22 '22 06:09

Matt Gallagher