Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent class from being subclassed in Objective-c

Tags:

objective-c

How do I prevent a particular class from being subclassed? I am not aware of such functionality (say final keyword for example) in the language. However Apple says it has done so for all classes in AddressBookUI.framework (in iOS)

For educational purposes, how can I achieve the same functionality, or how would they have done such thing?

From iOS7 Release Notes(Requires login) :

enter image description here

like image 359
nacho4d Avatar asked Oct 05 '13 06:10

nacho4d


2 Answers

Here's one way: override allocWithZone: from within your "final" class (substituting MyFinalClassName for your actual class name) like this:

+ (id)allocWithZone:(struct _NSZone *)zone
{
    if (self != [MyFinalClassName class]) {
        NSAssert(nil, @"Subclassing MyFinalClassName not allowed.");
        return nil;
    }

    return [super allocWithZone:zone];
}

This will prevent a subclass that is not a member of MyFinalClassName from being alloc'ed (and therefore init'ed as well), since NSObject's allocWithZone: must be called eventually, and by refusing to call super from your "final" class, you will prevent this.

like image 76
smileyborg Avatar answered Oct 16 '22 06:10

smileyborg


There's a simpler way to prevent subclassing in Xcode 6 as a result of Swift interop. To prevent Swift classes from being subclassed in Objective-C the objc_subclassing_restricted is added to all class definitions in the {ProjectName}-Swift.h file.

You can use this in your projects:

#if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
# define FOO_FINAL __attribute__((objc_subclassing_restricted))
#else
# define FOO_FINAL
#endif

FOO_FINAL
@interface Foo : NSObject
@end

@interface Bar : Foo
@end

The compiler will halt on the definition of Bar with Cannot subclass a class with objc_subclassing_restricted attribute

like image 28
Brian Nickel Avatar answered Oct 16 '22 08:10

Brian Nickel