Does Objective-C support Generics?

I wonder whether Objective-C offers any support for generics?

For instance, consider a method:

-(void) sort: (NSMutableArray *) deck {
}

Is there any way for me to make it only deal with Deck of Cards?
Is something like this possible to enforce?

-(void) sort: (NSMutableArray <Card *>) deck {
}

Solution 1:

Objective-C supports lightweight Generics since 2015, with the Xcode 7.

The Xcode 7 compiler will give you the compiler warning if there is a type mismatch.

For example, the following line will raise a compiler warning as the second object in the array causes type mismatch. The array allows only NSString objects.

NSArray <NSString *> *myArray = [@"str2", @1, @"str2"];

Solution 2:

You can use the introspection tools offered by the objective-c runtime.

Basically, it means you can check if all objects in an array either are a kind of class (Class A or one subclass of it) or a member of class (class A), or if a objects conforms to a protocol or responds to a selector (a certain method is present).

-(void) sort: (NSMutableArray *) deck {
    for(id obj in deck){
        if(obj isKindOfClass:[A class]]){
            //this is of right class
        }
    }
}

You could write a Category method on NSArray that checkouts this on every object.

BOOL allAreKindOfA = [array allObjectsAreKindOfClass:[A class]];

Normally you actually don't need this very often, as you know what you put inside a collection.

If you need to check the type or ability of an object in a Array, this might be an indicator, that your Architecture is broken


Another option could be a subclass of NSMutableArray that only accepts certain classes. But be aware of the subclassing notes for NSMutableArray and NSArray, as these are Class-Clusters and therefore not easy to subclass.

Note: In my other answer I created a NSMutableArray subclass, that uses a block to test, if a certain requirement is fulfilled. If you test against class-membership, this will do exactly what you want. Use the second block for error handling.

Solution 3:

As of Xcode 7's release, Apple has added support for Objective-C generics.

NSArray <NSString *> *arrayOfStrings = @[@"a", @"b"];

NSDictionary <NSString *, NSDate *> *dictionaryOfDates = @{ @"a" : @1 };