You could make a category with an -addSomeClass: method to allow compile-time static type checking (so the compiler could let you know if you try to add an object it knows is a different class through that method), but there's no real way to enforce that an array only contains objects of a given class.
In general, there doesn't seem to be a need for such a constraint in Objective-C. I don't think I've ever heard an experienced Cocoa programmer wish for that feature. The only people who seem to are programmers from other languages who are still thinking in those languages. If you only want objects of a given class in an array, only stick objects of that class in there. If you want to test that your code is behaving properly, test it.
This is a relatively common question for people transitioning from strongly type languages (like C++ or Java) to more weakly or dynamically typed languages like Python, Ruby, or Objective-C. In Objective-C, most objects inherit from NSObject (type id) (the rest inherit from an other root class such as NSProxy and can also be type id), and any message can be sent to any object. Of course, sending a message to an instance that it does not recognize may cause a runtime error (and will also cause a compiler warning with appropriate -W flags). As long as an instance responds to the message you send, you may not care what class it belongs to. This is often referred to as "duck typing" because "if it quacks like a duck [i.e. responds to a selector], it is a duck [i.e. it can handle the message; who cares what class it is]".
You can test whether an instance responds to a selector at run time with the -(BOOL)respondsToSelector:(SEL)selector method. Assuming you want to call a method on every instance in an array but aren't sure that all instances can handle the message (so you can't just use NSArray's -[NSArray makeObjectsPerformSelector:], something like this would work:
for(id o in myArray) {
if([o respondsToSelector:@selector(myMethod)]) {
[o myMethod];
}
}
If you control the source code for the instances which implement the method(s) you wish to call, the more common approach would be to define a @protocol that contains those methods and declare that the classes in question implement that protocol in their declaration. In this usage, a @protocol is analogous to a Java Interface or a C++ abstract base class. You can then test for conformance to the entire protocol rather than response to each method. In the previous example, it wouldn't make much of a difference, but if you were calling multiple methods, it might simplify things. The example would then be:
for(id o in myArray) {
if([o conformsToProtocol:@protocol(MyProtocol)]) {
[o myMethod];
}
}
assuming MyProtocol declares myMethod. This second approach is favored because it clarifies the intent of the code more than the first.
Often, one of these approaches frees you from caring whether all objects in an array are of a given type. If you still do care, the standard dynamic language approach is to unit test, unit test, unit test. Because a regression in this requirement will produce a (likely unrecoverable) runtime (not compile time) error, you need to have test coverage to verify the behavior so that you don't release a crasher into the wild. In this case, peform an operation that modifies the array, then verify that all instances in the array belong to a given class. With proper test coverage, you don't even need the added runtime overhead of verifying instance identity. You do have good unit test coverage, don't you?
You could subclass NSMutableArray to enforce type safety.
NSMutableArray is a class cluster, so subclassing isn't trivial. I ended up inheriting from NSArray and forwarded invocations to an array inside that class. The result is a class called ConcreteMutableArray which is easy to subclass. Here's what I came up with:
I created a NSArray subclass that is using an NSArray object as backing ivar to avoid issues with the class-cluster nature of NSArray. It takes blocks to accept or decline adding of an object.
to only allow NSString objects, you can define an AddBlock as
You can define a FailBlock to decide what to do, if an element failed the test — fail gracefully for filtering, add it to another array, or — this is default — raise an exception.
Have a look at https://github.com/tomersh/Objective-C-Generics, a compile-time (preprocessor-implemented) generics implementation for Objective-C. This blog post has a nice overview. Basically you get compile-time checking (warnings or errors), but no runtime penalty for generics.
It's important to note that these are compiler warnings only and you can technically still insert any object into your array. There are scripts available that turn all warnings into errors which would prevent building.
If you mix c++ and objective-c (i.e. using mm file type), you can enforce typing using pair or tuple. For example, in the following method, you can create a C++ object of type std::pair, convert it to an object of OC wrapper type (wrapper of std::pair that you need to define), and then pass it to some other OC method, within which you need to convert the OC object back to C++ object in order to use it. The OC method only accepts the OC wrapper type, thus ensuring type safety. You can even use tuple, variadic template, typelist to leverage more advanced C++ features to facilitate type safety.