views:

323

answers:

3

I have created a protocol that my classes need to implement, and then factored out some common functionality into a base class, so I did this:

@protocol MyProtocol
- (void) foo;
- (void) bar;
@end

@interface Base <MyProtocol>
@end

@interface Derived_1 : Base
@end

@interface Derived_2 : Base
@end

@implementation Base
- (void) foo{
//something foo
}
@end

@implementation Derived_1
- (void) bar{
//something bar 1
}
@end

@implementation Derived_2
- (void) bar{
//something bar 2
}
@end

In this way in my code I use a generic id<MyProtocol>.

The code works (as long as Base is not used directly) but the compiler chokes at the end of the implementation of Base with a warning:

Incomplete implementation of class Base

Is there a way to avoid this warning or, even better, a more proper way to obtain this partially implemented abstract base class behavior in Objc?

+4  A: 

In your protocol definition, you need to declare your methods under the @optional keyword.

Your code should look like this:

@protocol MyProtocol

@optional
- (void) foo;
- (void) bar;

@end

See this question on SO.

Jacob Relkin
Won't @optional make the method implementation optional also in derived classes?I want the most derived class to be forced to implement the methods not implemented in the base class ("bar", in this case).
garph0
@garph0, You cannot pick and choose in Obj-C.
Jacob Relkin
A: 

In Obj-C, there is no concept of abstract class. So that, you can not let your Base class to be abstract (which means dont' implements all methods in the protocol). You can only have 2 choices. Let the method in protocol to be optionol and then implements it yourself in the derived class. Or, force all classes in the hierarchy to implement it, but let the caller to be careful not call the incorrect method ones

vodkhang
+1  A: 

You could conceivably do something like this:

@implementation Base

- (void)bar
{
    if ([self class] == [Base class]) {
        [self doesNotRecognizeSelector:_cmd];
    }
}

@end

That way, you have an implementation, but by default it raises an exception. However, if a derived class accidentally calls [super bar] or does not override bar, then the exception won't be raised. If that's not what you want, you could just shorten it to:

@implementation Base

- (void)bar
{
    [self doesNotRecognizeSelector:_cmd];
}

@end

In which case, an exception will be raised, even if a subclass calls [super bar] or does not override bar.

mipadi
ok, this will at least enforce the implementation in the most derived classes.It would be nice to have a compile time warning for unimplemented methos, though, but I suppose there is no way (?)Is there a correct way to do this Base class partial implementation in Obj-c?
garph0
Not really. As others have noted, Objective-C does not have abstract base classes. Every approach I've ever used to emulate them only gets you part way there.
mipadi