Question

How to preventing inheritance in Objective-C?

I need to either prevent it, or issue a compiler warning referring to the projects documentation.

I came up with the following, which I am not sure if works in all scenarios.

main

#import <Foundation/Foundation.h>
#import "Child.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Child *c = [[Child alloc] init];
    }

    return TRUE;
}

Parent Class

.h

#import <Foundation/Foundation.h>

@interface Parent : NSObject

@end

.m

#import "Parent.h"

@implementation Parent

+ (id)allocWithZone:(NSZone *)zone {
    NSString *callingClass = NSStringFromClass([self class]);
    if ([callingClass compare:@"Parent"] != NSOrderedSame) {
        [NSException raise:@"Disallowed Inheritance." format:@"%@ tried to inherit Parent.", callingClass];
    }
    return [super allocWithZone:zone];
}

@end

Child Class

.h

#import <Foundation/Foundation.h>
#import "Parent.h"

@interface Child : Parent

@end

.m

#import "Child.h"

@implementation Child

@end
Was it helpful?

Solution

the general approach looks good to me but why the string compare? Going after the class's name doesn't seem clean

here's a variant that does it comparing the Class objects:

#import <Foundation/Foundation.h>

@interface A : NSObject 
@end
@implementation A
+ (id)allocWithZone:(NSZone *)zone {
    Class cls = [A class];
    Class childCls = [self class];

    if (childCls!=cls) {
        [NSException raise:@"Disallowed Inheritance." format:@"%@ tried to inherit %@.", NSStringFromClass(childCls), NSStringFromClass(cls)];
    }
    return [super allocWithZone:zone];
}
    @end

@interface B : A
@end
@implementation B
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        A *a = [[A alloc] init];
        NSLog(@"%@",a);
        B *b = [[B alloc] init];
        NSLog(@"%@",b);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top