Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 702 Vote(s) - 3.44 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Creating an abstract class in Objective-C

#1
I'm originally a Java programmer who now works with Objective-C. I'd like to create an abstract class, but that doesn't appear to be possible in Objective-C. Is this possible?

If not, how close to an abstract class can I get in Objective-C?
Reply

#2
Instead of trying to create an abstract base class, consider using a protocol (similar to a Java interface). This allows you to define a set of methods, and then accept all objects that conform to the protocol and implement the methods. For example, I can define an Operation protocol, and then have a function like this:

- (void)performOperation:(id<Operation>)op
{
// do something with operation
}

Where op can be any object implementing the Operation protocol.

If you need your abstract base class to do more than simply define methods, you can create a regular Objective-C class and prevent it from being instantiated. Just override the - (id)init function and make it return nil or assert(false). It's not a very clean solution, but since Objective-C is fully dynamic, there's really no direct equivalent to an abstract base class.
Reply

#3
Using `@property` and `@dynamic` could also work. If you declare a dynamic property and don't give a matching method implementation, everything will still compile without warnings, and you'll get an `unrecognized selector` error at runtime if you try to access it. This essentially the same thing as calling `[self doesNotRecognizeSelector:_cmd]`, but with far less typing.
Reply

#4
Typically, Objective-C class are abstract by convention only—if the author documents a class as abstract, just don't use it without subclassing it. There is no compile-time enforcement that prevents instantiation of an abstract class, however. In fact, there is nothing to stop a user from providing implementations of abstract methods via a category (i.e. at runtime). You can force a user to at least override certain methods by raising an exception in those methods implementation in your abstract class:

[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];

If your method returns a value, it's a bit easier to use

@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];

as then you don't need to add a return statement from the method.

If the abstract class is really an interface (i.e. has no concrete method implementations), using an Objective-C protocol is the more appropriate option.
Reply

#5
(more of a related suggestion)

I wanted to have a way of letting the programmer know "do not call from child" and to override completely (in my case still offer some default functionality on behalf of the parent when not extended):

typedef void override_void;
typedef id override_id;

@implementation myBaseClass

// some limited default behavior (undesired by subclasses)
- (override_void) doSomething;
- (override_id) makeSomeObject;

// some internally required default behavior
- (void) doesSomethingImportant;

@end

The advantage is that the programmer will SEE the "override" in the declaration and will know they should not be calling `[super ..]`.

Granted, it is ugly having to define individual return types for this, but it serves as a good enough visual hint and you can easily not use the "override_" part in a subclass definition.

Of course a class can still have a default implementation when an extension is optional. But like the other answers say, implement a run-time exception when appropriate, like for abstract (virtual) classes.

It would be nice to have built in compiler hints like this one, even hints for when it is best to pre/post call the super's implement, instead of having to dig through comments/documentation or... assume.

![example of the hint][1]


[1]:
Reply

#6
Just riffing on @Barry Wark's answer above (and updating for iOS 4.3) and leaving this for my own reference:


#define mustOverride() @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"%s must be overridden in a subclass/category", __PRETTY_FUNCTION__] userInfo:nil]
#define methodNotImplemented() mustOverride()


then in your methods you can use this

- (void) someMethod {
mustOverride(); // or methodNotImplemented(), same thing
}



<BR><BR>
**Notes:** Not sure if making a macro look like a C function is a good idea or not, but I'll keep it until schooled to the contrary. I think it's more correct to use `NSInvalidArgumentException` (rather than `NSInternalInconsistencyException`) since that's what the runtime system throws in response to `doesNotRecognizeSelector` being called (see `NSObject` docs).
Reply

#7
In Xcode (using clang etc) I like to use `__attribute__((unavailable(...)))` to tag the abstract classes so you get an error/warning if you try and use it.

It provides some protection against accidentally using the method.

### Example

In the base class `@interface` tag the "abstract" methods:

- (void)myAbstractMethod:(id)param1 __attribute__((unavailable("You should always override this")));

Taking this one-step further, I create a macro:

#define UnavailableMacro(msg) __attribute__((unavailable(msg)))

This lets you do this:

- (void)myAbstractMethod:(id)param1 UnavailableMacro(@"You should always override this");

Like I said, this is not real compiler protection but it's about as good as your going to get in a language that doesn't support abstract methods.
Reply

#8
Probably this kind of situations should only happen at development time, so this might work:

- (id)myMethodWithVar:(id)var {
NSAssert(NO, @"You most override myMethodWithVar:");
return nil;
}
Reply

#9
This thread is kind of old, and most of what I want to share is already here.

However, my favorite method is not mentioned, and AFAIK there’s no native support in the current Clang, so here I go…

First, and foremost (as others have pointed out already) abstract classes are something very uncommon in Objective-C — we usually use composition (sometimes through delegation) instead. This is probably the reason why such a feature doesn’t already exist in the language/compiler — apart from `@dynamic` properties, which IIRC have been added in ObjC 2.0 accompanying the introduction of CoreData.

But given that (after careful assessment of your situation!) you have come to the conclusion that delegation (or composition in general) isn’t well suited to solving your problem, here’s how _I_ do it:

1. Implement every abstract method in the base class.
2. Make that implementation `[self doesNotRecognizeSelector:_cmd];`…
3. …followed by `__builtin_unreachable();` to silence the warning you’ll get for non-void methods, telling you “control reached end of non-void function without a return”.
4. Either combine steps 2. and 3. in a macro, or annotate `-[NSObject doesNotRecognizeSelector:]` using `__attribute__((__noreturn__))` in a category **without implementation** so as not to replace the original implementation of that method, and include the header for that category in your project’s PCH.

I personally prefer the macro version as that allows me to reduce the boilerplate as much as possible.

Here it is:

// Definition:
#define D12_ABSTRACT_METHOD {\
[self doesNotRecognizeSelector:_cmd]; \
__builtin_unreachable(); \
}

// Usage (assuming we were Apple, implementing the abstract base class NSString):
@implementation NSString

#pragma mark - Abstract Primitives
- (unichar)characterAtIndex:(NSUInteger)index D12_ABSTRACT_METHOD
- (NSUInteger)length D12_ABSTRACT_METHOD
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange D12_ABSTRACT_METHOD

#pragma mark - Concrete Methods
- (NSString *)substringWithRange:(NSRange)aRange
{
if (aRange.location + aRange.length >= [self length])
[NSException raise:NSInvalidArgumentException format:@"Range %@ exceeds the length of %@ (%lu)", NSStringFromRange(aRange), [super description], (unsigned long)[self length]];

unichar *buffer = (unichar *)malloc(aRange.length * sizeof(unichar));
[self getCharacters:buffer range:aRange];

return [[[NSString alloc] initWithCharactersNoCopy:buffer length:aRange.length freeWhenDone:YES] autorelease];
}
// and so forth…

@end

As you can see, the macro provides the full implementation of the abstract methods, reducing the necessary amount of boilerplate to an absolute minimum.

An even better option would be to [lobby the](

[To see links please register here]

) [Clang team](

[To see links please register here]

) to providing a compiler attribute for this case, via feature requests. (Better, because this would also enable compile-time diagnostics for those scenarios where you subclass e.g. NSIncrementalStore.)

## Why I Choose This Method

1. It get’s the job done efficiently, and somewhat conveniently.
1. It’s fairly easy to understand. (Okay, that `__builtin_unreachable()` may surprise people, but it’s easy enough to understand, too.)
1. It cannot be stripped in release builds without generating other compiler warnings, or errors — unlike an approach that’s based on one of the assertion macros.

That last point needs some explanation, I guess:

Some (most?) people strip assertions in release builds. (I disagree with that habit, but that’s another story…) Failing to implement a required method — however — is **bad**, **terrible**, **wrong**, and **basically the end of the universe** for your program. Your program cannot work correctly in this regard because it is undefined, and undefined behavior is the worst thing ever. Hence, being able to strip those diagnostics without generating new diagnostics would be completely unacceptable.

It’s bad enough that you cannot obtain proper compile-time diagnostics for such programmer errors, and have to resort to at-run-time discovery for these, but if you can plaster over it in release builds, why try having an abstract class in the first place?
Reply

#10
Another alternative

Just check the class in the Abstract class and Assert or Exception, whatever you fancy.


@implementation Orange
- (instancetype)init
{
self = [super init];
NSAssert([self class] != [Orange class], @"This is an abstract class");
if (self) {
}
return self;
}
@end


This removes the necessity to override `init`
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through