3

I was reading Creating an abstract class in Objective-C, and I wasn't terribly satisfied with the fact that the "abstractness" of the class is only enforced at runtime. I'd like to be able to show some warnings if the method is not implemented in a subclass. Ideally, this could be condensed down to one or two #defines.

Is there a clever use of __attribute((available,deprecated,etc))__ or a #warning with some careful #pragma clang diagnostic pushes that can accomplish this?

I think this is possible; I just don't know enough about Clang to figure it out.

EDIT:

There's no need to tell me I should be using protocols. I already use them for this purpose. I'm more curious to see if it can be done (to learn more about Clang) than whether it should be done.

I see this working the in a similar way to NSManagedObject requiring properties to be marked @synthesized or @dynamic. I've researched this, and I see that in NSManagedObject.h the class is marked NS_REQUIRES_PROPERTY_DEFINITIONS, which translates to __attribute__((objc_requires_property_definitions)) in NSObjCRuntime.h. Is there some creative use of these built-in #defines that could make this work?

EDIT #2:

For people saying that abstract superclasses are not the Objective-C way, I'll direct you to the documentation for UIMotionEffects:

Subclassing Notes

This class is abstract and cannot be instantiated directly.

Community
  • 1
  • 1
paulrehkugler
  • 3,241
  • 24
  • 45
  • 3
    You can define a protocol, which delegates should be implementing its methods. – Alexander Perechnev Dec 05 '13 at 20:36
  • Good question. In Java for a while, people were proposing using aspects for this and having them generate warnings/errors that would be surfaced during compilation. – Rob Dec 05 '13 at 20:36
  • This is probably not what you're looking for, but you could define a protocol for the required methods, and make sure you define the subclass to conform to this protocol. That way the compiler will tell you what methods need to be implemented. – Rob Dec 05 '13 at 20:36
  • like told, use a protocol and you can define if something is `@required` or `@optional` – Alex Cio Dec 05 '13 at 20:38
  • @JuJoDi that question says nothing about creating warnings – paulrehkugler Dec 05 '13 at 20:48
  • 1
    You can NSAssert if you'd like, but the point is that Objective-C isn't built to virtualize classes entirely like you're trying to do. If you google Objective-C pure virtual class though, you'll find many attempts at a solution – JuJoDi Dec 05 '13 at 20:50
  • @AlexanderPerechnev I could define a protocol, but the problem with that is that all subclasses need to implement the protocol, but the superclass doesn't. I'd just like to know how/if it's possible to make these warnings in the subclass if it doesn't implement the superclass method. – paulrehkugler Dec 05 '13 at 20:51
  • @JuJoDi NSAssert also doesn't give a compile-time warning, it throws a runtime exception – paulrehkugler Dec 05 '13 at 20:51
  • 1
    You're still attempting to use Objective-C in a way that it was not intended – JuJoDi Dec 05 '13 at 21:03

2 Answers2

4

I prefer the NSException approach (which is a run-time, not a compile time, error).

In your superclass:

@interface NSSuperclass : NSObject

- (void)execute;

@end


@implementation NSSuperclass

- (void)execute
{
    @throw [NSException exceptionWithName:NSInternalInconsistencyException
                                   reason:[NSString stringWithFormat:@"Called %@ on superclass NSSuperclass, this should only be called on subclasses", NSStringFromSelector(_cmd)]
                                 userInfo:@{@"object": self}];
}

@end

And then override this method in your subclasses.

Joel Fischer
  • 6,521
  • 5
  • 35
  • 46
3

I go for protocol

untested code, the idea is use protocol type (maybe combined with class type) instead of just class type.

@interface BaseClass : NSObject

- (void)foo;

@end

@protocol BaseClassProtocol : NSObject

@required
- (void)bar;

@end

@interface SubClass : BaseClass <BaseClassProtocol>

@end

@interface SubClass2 : BaseClass // no <BaseClassProtocol>

@end

// some code

BaseClass <BaseClassProtocol> * obj = [SubClass new]; // good
BaseClass <BaseClassProtocol> * obj = [SubClass2 new]; // warning
GeneralMike
  • 2,951
  • 3
  • 28
  • 56
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • I guess this is the Objective-C way of doing things, but I already know about protocols and they're not what I was looking for – paulrehkugler Dec 05 '13 at 20:59
  • 2
    @paulrehkugler if you really want the C++ style abstract class, use Objective-C++ and use C++ pure virtual function with C++ class – Bryan Chen Dec 05 '13 at 21:05
  • What if a SubClass method needs to call [super bar]; ? It's a problem because BaseClass can't publicly implement the protocol because then it is no longer abstract, but it has to somewhere otherwise super bar can't be called inside SubClass. Maybe using a private class extension shared inside the SubClass.m? – malhal Jan 03 '18 at 01:51
  • @malhal there is no `[BaseClass bar]` method so it doesn't make sense to call `[super bar]` from subclass. Unless you want to call it from sub-subclass, which shouldn't have any issue. – Bryan Chen Jan 07 '18 at 00:24