94

I was reading that NSArray is just such a thing. Sounds heavy. I have 7 really fat books here on my desk about Objective-C, Cocoa and C. None of them mention Class Cluster at all, at least I can't find it in the Index at the back of the books. So what's that?

Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
openfrog
  • 40,201
  • 65
  • 225
  • 373
  • Oops, next time i'll think to add a link for that term. If you would have commented on the answer to you previous question i'd have responded there. – Georg Fritzsche Dec 04 '09 at 01:35
  • 2
    FWIW: recently (Dec 2013) Apple recommended using Class Clusters as a way to handle backward-compatibilty to iOS 6 while using iOS 7. This was on Apple Tech Talks 2013/Berlin in the session "Architecting Modern Apps, Part 2". Apple said that they will be posting videos of the sessions shortly after the last event (17. Dec). So maybe this will help to understand Class Clusters within the actual context of the iOS 6/7 changes. – brainray Dec 17 '13 at 12:42

5 Answers5

195

I don't know what is in the CDP that Steve referenced but basically the Objective-C Class Cluster is a construct that supports implementing the abstract Factory pattern.

The idea is simple: You want to provide a Factory (Cluster) interface that, with minimal description, manufactures and returns a specific concrete instance of a Factory Object that satisfies the behavior of the cluster family described by the Factory (Cluster) interface.

A simple concrete example: This example provides a Laugh factory that produces concrete classes of specific laughter types (e.g. Guffaw, Giggle). Pay attention to the Laugh initWithLaughter: method.

In Laugh.h:

#define kLaughWithGuffaw  1
#define kLaughWithGiggle  2

@interface Laugh: NSObject {}
- (Laugh *) initWithLaughter:(NSUInteger) laughterType;
- (void) laugh;
@end

In Laugh.m:

@interface Guffaws:Laugh {}
- (void) laugh;
@end

@interface Giggles:Laugh {}
- (void) laugh;
@end

@implementation Laugh
- (Laugh *) initWithLaughter:(NSUInteger) laugherType {
    id instanceReturn=nil;
    ; // Removed for ARC [self release]
    if ( laughterType == kLaughWithGuffaw )
        instanceReturn = [[Guffaws alloc]init];
    else if( laughterType == kLaughWithGiggle )
        instanceReturn = [[Giggles alloc]init];
    else
        ; // deal with this
    return instanceReturn;
}

- (void) laugh {
    NSLog(@"Humbug");
}
@end

@implementation Guffaws
    - (void) laugh {
        NSLog(@"OH HA HA HOWAH HA HA HA");
    }
@end

@implementation Giggles
    - (void) laugh {
        NSLog(@"Tee hee");
    }
@end
Frank C.
  • 7,758
  • 4
  • 35
  • 45
  • 24
    While the other answers were good providing doc & book links, I like this because it makes it nice and simple to see how to actually do this. Thanks – jamone Apr 26 '11 at 17:31
  • This example is good but in a typical Factory pattern the subclasses are public. In a Class cluster the subclasses are private. http://developer.apple.com/library/ios/documentation/general/Conceptual/DevPedia-CocoaCore/ClassCluster.html – maxpower May 17 '13 at 02:20
  • Are the subclasses private by convention or actually private? – anavarroma Aug 05 '13 at 10:10
  • 1
    @AdriàNavarro They are not visible to the outside since they are declared in the `.m-file`. – hfossli Jan 09 '14 at 09:55
  • 4
    **(1)** How safe is it to release self in an `init` method, and return something else? Are there any code examples from Apple where they do this? **(2)** Also, you are presumably creating an instance with code such as `[[Laugh alloc] initWithLaughter:kLaughWithGiggle]`. Notice how `Laugh` is being unnecessarily allocated, since it will be released immediately after this call. Why do it this way when you can create a class method such as `[Laugh laughWithLaughter:kLaughWithGiggle]` which gives you all the advantages of private subclasses, while avoiding issues 1 & 2 above? – Senseful Jun 26 '14 at 19:13
  • Needs updating for iOS 8! – Hyperbole Oct 01 '14 at 14:43
  • 1
    @Senseful You're right. In real life, `+alloc` returns a singleton factory class that implements the various `-initWith:` methods. The factory class's `-initWith:` methods are then responsible for allocating and initializing a concrete subclass based on the given method parameters, if necessary, or in some cases may not allocate anything at all (such as `-[NSString initWithString:]`). You can try it by inspecting at the return value of `+[NSString alloc]`, `+[NSArray alloc]`, etc. – Darren Dec 18 '14 at 21:08
44

From Apple's docs.... In short it's a design pattern used in the Foundation framework, which is probably why it's not mentioned in ObjC books.

A class cluster is an architecture that groups a number of private, concrete subclasses under a public, abstract superclass. The grouping of classes in this way provides a simplified interface to the user, who sees only the publicly visible architecture.

zwcloud
  • 4,546
  • 3
  • 40
  • 69
echo
  • 7,737
  • 2
  • 35
  • 33
  • 1
    roflmao. thanks. gonna google next time. thought if its not in my fat books, it can only be on your heads ;) – openfrog Dec 04 '09 at 17:34
  • 1
    The one thing this link is missing is an explanation on how to best alter the implementation for ARC. – Hyperbole Nov 01 '12 at 21:33
26

From programming in objective c by Stephen Kochan on page 498 in the glossary, cluster:

An abstract class that groups a set of private concrete subclasses, providing a simplified interface to the user through the abstract class.

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
t011phr33
  • 271
  • 2
  • 2
  • 5
    +1 For quoting an answer from an Objective-C book, particularly given the original question. That's a good book, too. – Quinn Taylor Dec 04 '09 at 22:57
  • (+1) for the excellent definition. The problem I have with calling this a "Factory" pattern is that such a name focuses on just the *creation* of objects, not the under-the-hood interactions of the private subclasses as managed by the abstract superclass. Indeed, even calling this superclass "abstract" could be misleading as it is in fact quite (internally) dependent upon its own subclasses, and is therefore not a normal abstract class which generally does not know anything about its subclasses. – devios1 Jan 08 '15 at 18:53
18

Class clusters provide a single public interface to a group of concrete, private subclass implementations. An objective-c programmer uses class clusters often and rarely realizes it - and this is the whole point of a class cluster. A class cluster's job is to hide the complexity of implementation detail behind a public interface.

Many of the Foundation classes are class clusters, such as NSString, NSArray, NSDictionary, and NSNumber. When you call [NSString stringWithFormat:] the class cluster is giving you some concrete class that implements the NSString interface. It could be an NSConcreteString, NSCFString, NSFooBarString, etc. Which the class cluster gives you is based on the constructor or initializer you are calling and the arguments.

Because of this, class clusters are one of the most empowering concepts in Objective-C programming.

  • Very easy to implement
  • Easy to change the underlying implementation without changing the code that calls it.
  • Easy to provide different concrete implementations at runtime (i.e. test resources or mock objects)
  • Because of the above, easy to test and refactor

If you are coming from other languages you may be familiar with the Gang of Four patterns. Class clusters have elements of both the abstract factory and the facade patterns.

Apple's public documentation covers class clusters (and how to implement and extend them) quite extensively. Unfortunately, I have found that for many iOS developers this and other Cocoa-specific patterns are a blind spot.

Cocoa Core Competencies: Class cluster

Cocoa Fundamentals Guide: Class Clusters

Examples of how to implement your own class clusters are available on GitHub

quellish
  • 21,123
  • 4
  • 76
  • 83
7

The NSArray class cluster isn't "heavyweight", it's a way for any number of implementations of an array class to be used without your code knowing or caring about the particular implementation. Under the hood, there are concrete subclasses of NSArray that are appropriate to different use cases, such as large, sparse arrays, or arrays containing a specific number of elements that are known at compile time.

NSArray, NSString, and NSNumber are the class clusters you'll most often encounter.

NSResponder
  • 16,861
  • 7
  • 32
  • 46
  • 6
    Ironically, in practice, only one concrete class per cluster is ever used anymore — NSCF{Array|String|Number} — and the implementation changes are internal to that class. That's as far as I know, anyway. Even NSArray and NSMutableArray instances show up the same class. – Chuck Mar 17 '10 at 02:02
  • 1
    @Chuck - how can this be the case? If a NSMutableArray and NSArray reported themselves to be the same class wouldn't `[myArray isKindOfClass:[NSMutableArray class]]` return YES even though it should not? – Robert Feb 26 '13 at 11:41
  • 2
    @Robert: And indeed that was the case at the time of my comment. Nowadays Apple has replaced NSCFArray with __NSArrayM and __NSArrayI, so I think it's no longer so, but I still wouldn't feel comfortable depending on it, as they could always change it again. – Chuck Feb 26 '13 at 19:26