Coming from other object oriented programming languages, sooner or later any Mac or iPhone developer will find himself thinking on a Cocoa development design that includes abstract classes. However, The concept of “abstract class” in Objective-C means something completely different. In Objective-C, an abstract class is a class whose instances can, actually, be represented internally by a bunch of different classes. One example is NSString. NSString is defined as an abstract class, meaning that, when you create a new instance of NSString and use it, you are internally using another class, not NSString, but a “kind of” NSString. That’s why you should never check whether an id object is a string by asking isMemberOf:, because it would never be a NSString internally, you should use isKindOf:. While the former checks the formal class of the object, the later checks if it belongs to a “common family” of classes. Thus, you can instantiate an abstract class in Objective-C (NSString is a prime example), while you cannot do this on a Java abstract class.

❤️ Enjoying this post so far?

If you find this content useful, consider showing your appreciation by buying me a coffee using the button below 👇.

Buy me a coffeeBuy me a coffee

This conceptual difference is important, because you cannot just define an abstract class, and then define some subclasses, safely knowing that nobody would be able to instantiate your superclass. However, we can try to replicate this scheme in Objective-C by using some tricks. Here is how:

First, create a superclass that will be the “abstract class”. Let’s say we call this class MyObject. We will define it as:

@interface MyObject: NSObject

@property (nonatomic, strong) NSString * someProperty;

- (id) initWithCustomObject: (id) customObject;
- (id) someMethodWithArgument: (id) someArgument;
@end

Here we have an initializer, initWithCustomObject:, and an instance method, someMethodWithArgument:. We cannot forbid a declaration at a compiling time, but we can enforce a runtime error if someone tries to instantiate or use a method of this class. For that, we will use the NSObject method doesNotRecognizeSelector:, that effectively raises an error when trying to use some selector. In our case, we will select _cmd, that means the current selector being invoked. Thus, our implementation will look like:

@implementation MyObject

@synthesize someProperty = _someProperty;

- (id) initWithCustomObject: (id) customObject {
   if ([self isMemberOf:[MyObject class]]) {
      [self doesNotRecognizeSelector:_cmd]);
      return nil;
   } else {
      self = [super init];
      if (self) {
         // common initialization for this hierarchy of classes
      }
   }
}

- (id) someMethodWithArgument: (id) someArgument {
   [self doesNotRecognizeSelector:_cmd];
   return nil;
}

@end

Here, by using isMemberOf:, we test whether the invoking class is exactly of type “MyObject”. Subclasses of MyObject (i.e: MyObjectSubclass1) will return NO for isMemberOf:, although they will return YES for isKindOf:. Thus, in our subclasses, we just need to define the initializer and methods, and we could use safely [super init] in the initializer. The public property will be, of course, available for the subclasses.

But what happens if we want to declare a private property? That’s a more tricky case. As Objective-C doesn’t have the concept of “protected” methods and variables like other languages (C++, Java…), there is no way to define a property that will be available for this class and its subclasses only, but we can use another method for replicating this functionality. We just need to declare the property again in the subclass private interface, and then, instead of synthesizing it, declaring it as a @dynamic property at the implementation. In this way, the subclass will know that the property is defined and synthesized somewhere in the superclass.

The private interface and implementation (.m) of the superclass:

@interface MyObject ()

@property (nonatomic, strong) NSString * privateProperty;

@end

@implementation MyObject

@synthesize privateProperty = _privateProperty;

@end

 

The private interface and implementation (.m) of the subclass:

@interface MyObjectSubclass ()

@property (nonatomic, strong) NSString * privateProperty;

@end

@implementation MyObjectSubclass

@dynamic privateProperty;

@end

 

So I hope to have helped you in case you are looking for an abstract class scheme for your next project.