Abstract class in Objective-C - objective-c

I need your help. Following problem in Objective-C:
// Robot.h
#protocol RobotProtocol <NSObject>
-(void)doWork;
#end
#interface Robot : NSObject
// Rob1 sublass of class Robot
// rob1.h
#interface Rob1 : Robot <RobotProtocol>
// rob1.m
#implementation
-(void)doWork
{
// print 'robot 1'
}
// Rob2 sublass of class Robot
// rob2.h
#interface Rob2 : Robot <RobotProtocol>
// rob2.m
#implementation
-(void)doWork
{
// print 'robot 2'
}
// Task.h
#interface Task : NSObject
{
Robot *rob;
}
// Task.m
#implementation
- (id)init
{
if ([super init]) {
rob = [[Rob1 alloc] init]; // or Rob2 !!
}
return self;
}
-(void)doSomething
{
[rob doWork]; // how to make sure, that this is implemented, depending on Rob1 or Rob2
}
How should Robot and its subclasses be implemented, that Robot *rob can be one of the subclasses of Robot rob1, rob2, ... and the method doWork:(BOOL)val; can be called? My first idea was to implement Robot as an abstract class, but unfortunately there are no abstract classes in Objective-C...
At the moment I am using a protocol, but I am not confident. Because it is not sure, that doWork is implemented, the compiler complains about
'Robot' may not respond to 'doWork'
Thank you for your ideas.

Protocols should work.
#protocol RobotProtocol <NSObject>
#required
- (void)doWork:(BOOL)flag;
#end
#interface Robot1 : NSObject <RobotProtocol>
#end
#implementation Robot1
- (void)doWork:(BOOL)flag
{
}
#end
Unit Test for Robot1 called though id<RobotProtocol>
- (void)testRobot
{
id<RobotProtocol> robot = [[Robot1 alloc] init];
[robot doWork:YES];
}
Update
After looking at your code, #interface Robot : NSObject should be #interface Robot : NSObject <RobotProtocol>. The thing is you don't need #interface Robot : NSObject <RobotProtocol> at all. You can just use id<RobotProtocol>. This is the name of your abstract class.

As many stated, there are no abstract classes in Objective-C. Personally I go for comments + runtime check. Code like this:
#interface Abstract : NSObject {
}
// Abstract method
- (Foo*)doSomething;
#end
#implementation Abstract
// Abstract method
- (Foo*)doSomething {
[_self doesntRecognizeSelector:_cmd];
return nil;
}
#end
If you really want to use something "abstract" and have compile time checks, I think you'll have to use protocols. To do so you need to slightly change your code. Particularly you should declare your variable as conforming to protocol, either id<RobotProtocol> or Robot<RobotProtocol>* depending on what better suits your needs:
// Task.h
#interface Task : Robot <RobotProtocol>
{
id<RobotProtocol> rob;
}

I'm guessing you're trying to do something like this but without code it's hard to say...
//Robot.h
{
-(void)doWork:(BOOL)myBool
}
//Robot.m
{
-(void)doWork:(BOOL)myBool
{
if (myBool)
{
//do something
}
else
{
//do something else
}
}
}
//Task.h
{
#include"Robot.h"
}
//Task.m
{
Robot *rob = [[Robot rob] alloc] init];
[rob doWork:YES];
}

Objective-C does not have something called abstract classes like you have in java. Just create a superclass called Robot and subclass it.. you could potentially even block instancing the class by overriding init and immediately destroying itself ( though I am not too sure about the 'corectness' of such an approach.. )
In any case, it shouldn't be an issue.
Also a handy trick to figure out whether a certain object responds to a method is by using
if( [rob respondsToSelector:#selector(doWork:)] ) { [rob doWork:value]; }
this is often used in order to make methods in a protocol optional, so that you do not get errors at runtime when you call a method that does not exist for a given object.

Does whatever method is trying to call doWork know about the RobotProtocol protocol? You may need to import whatever header file contains it.
For what it's worth, the accepted way to do what you want is to just declare whatever the superclass is (Robot), declare and implement methods with empty bodies (possibly throwing an NSException if they aren't overwritten by a subclass) and create your subclass (SubRobot, or what have you). Protocols are more so different types of classes can implement a few known methods, not for use as de-facto abstract superclasses.

Related

How to define a `Class` object type conforming to a protocol?

Consider the following Objective-C protocol declaration, which requires only class methods:
#protocol TDWMethoding<NSObject>
+ (void)foo;
+ (void)bar;
#end
Assuming I need to return an instance of a Class which conforms to this protocol from a method, how am I supposed to specify the return type?
- (nullable /*return-type*/)instantiateMethoding {
Class instance = ... // some implementation
if ([instance conformsToProtocol:#protocol(TDWMethoding)]) {
return instance;
}
return nil;
}
There are a number of working options I considered so far in regards to how to express the /*return-type*/, but each has its own downsides:
Class - this way it doesn't expose conformance. What kind of Class is it? What does it do? Does it conform to the protocol at all?
Class<TDWMethoding> - this looks like a viable solution and even was suggested a few times by other developers (here and here) but I personally find it inconsistent and misleading: when we have a variable of form Type<Protocol> *instance, it commonly means that protocol class methods should be sent to the instance's class ([[instance class] foo]) not the instance itself ([instance foo]);
id<TDWMethoding> and returning an instance of the class instead - this is consistent, but it requires me to instantiate the class, which is both redundant and prevents me from hiding the constructors of the utility classes which conforms to the protocol with NS_UNAVAILABLE macro.
Is there a better semantic to express such a return-type?
Class<TDWMethoding> is correct. It's not inconsistent. When something is of type Class, you send class methods to it. When something is an instance, and you want to send to the class, you access its -class.
That said, this does seem very strange, and likely means you're overusing Class methods. You should think hard about whether a sharedInstance is a better model for this.
But if you want to identify the type, Class<TDWMethoding> is correct, though id would likely be more common, as discussed in How to cast Class object to conformance witih protocol.
After digging a little deeper into The Objective-C Programming Language documentation, I actually found the exact answer to such a scenario:
Protocols can’t be used to type class objects. Only instances can be statically typed to a protocol, just as only instances can be statically typed to a class. (However, at runtime, both classes and instances respond to a conformsToProtocol: message.)
Which means that it's just not supported and I should implement this differently. (e.g. with use of a singleton pattern, as suggested in Rob's answer)
The solution is doesn't use such protocols at all. Why? Because it's inflexible.
It should be just:
#protocol TDWMethoding
- (void)foo;
- (void)bar;
#end
Then you will be able to do any what you want, for example you will be able to create wrapper for yours class, that will be implementing yours protocol.
#interface TDWMethodingModel<TDWMethoding>
#property (nonatomic, readonly) void (^fooCaller)(void);
#property (nonatomic, readonly) void (^barCaller)(void);
- (instancetype)initWithFooCaller:(void (^)(void))fooCaller barCaller:(void (^)(void))barCaller NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
#end
#implementation TDWMethodingModel
- (instancetype)initWithFooCaller:(void (^)(void))fooCaller barCaller:(void (^)(void))barCaller {
self = [super init];
if (nil == self) {
return nil;
}
_fooCaller = fooCaller;
_barCaller = barCaller;
return self;
}
- (void)foo {
self.fooCaller();
}
- (void)bar {
self.barCaller();
}
#end
then:
- (id<TDWMethoding>)instantiateMethoding
{
static id<TDWMethoding> methoding;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
methoding = [[TDWMethodingModel alloc] initWithFooCaller:^{
[SomeClass foo];
} barCaller:^{
[SomeClass bar];
}];
});
return methoding;
}

Objective C: incompatible pointer types sending

I created a protocol, called EventListener:
#protocol EventListener
...
#end
I also have class, Processor, like:
// Processor.m
#synthesize listeners = _listeners; //#property NSMutableArray* in Processor.h
- (id) init {
self = [super init];
self.listeners = [[NSMutableArray alloc] init]; //init with empty array
return self;
}
- (void) addListener:(id<EventListener>)listener {
[self.listeners addObject:listener];
}
I have another class, called Plugin:
#interface Plugin : NSObject <EventListener> { ... }
...
#end
and in its implementation, I perform:
// Plugin.m
[self.processor addListener:self];
and get warning that
incompatible pointer types sending Plugin* sending to parameter of type Listener*
What I've done wrong?
I'm coming from java world and assume that because my Processor implements protocol it should be type of Listener, smith like:
interface Listener {
}
class Processor {
List<Listener> listeners = new ArrayList<Listener>();
void addListener(Listener listener) {
listeners.add(listener);
}
}
class Plugin implements Listener {
Processor processor = new Processor();
void method() {
processor.addListener(this);
}
}
In Objective-C, classes and protocols are completely separate things and — unlike Java's classes and interfaces — have distinct syntax.
If you wanted to accept any class which is, or is a descendant of, the class Listener then the parameter would be:
Listener *
If you wanted to accept any class that implements the protocol EventListener then the parameter would be:
id <EventListener>
As id means "any class type" and the <EventListener> adds that whatever is passed should implement that protocol.
If you wanted to accept only those of Listener and its subclasses that implement EventListener then the parameter would be:
Listener <EventListener> *
That contrasts with Java where you'd take the interface type directly and not specify any class type constraints.
You can get the same warning when you declared
#interface SomeClass <SomeProtocol> : NSObject
#end
instead of
#interface SomeClass : NSObject<SomeProtocol>
#end
The first syntax is correct but it has no sense.

Implementing a category on all classes conforming to a protocol

I have written a category on SCNRenderer that adds some camera utility methods. Those same methods would be equally useful to SCNView and SCNLayer. All three of the classes to which this category would be relevant conform to SCNSceneRenderer. Is it possible to write a category that applies not to a specific class, but to all classes that conform to a particular protocol?
The simplest way of doing this would be to write some utility functions that take an SCNSceneRenderer object:
void ABCDoSomethingUseful(id<SCNSceneRenderer> renderer)
{
//...
}
void ABCDoSomethingElseUseful(id<SCNSceneRenderer> renderer)
{
//...
}
If you want to use the method call syntax, or want to be able to override the implementation in subclasses, another option would be to implement the methods as a category on NSObject:
// This goes in a source file:
#interface NSObject (SCNSceneRendererConformance) <SCNSceneRenderer>
// Surpress compiler warnings about NSObject not responding to
// SCNSceneRenderer's messages
#end
#implementation NSObject (MyCategory)
- (void)abc_doSomethingUseful
{
//...
}
- (void)abc_doSomethingElseUseful
{
//...
}
#end
then expose them in a protocol:
// This goes in a header file:
#protocol MyProtocol <NSObject>
- (void)abc_doSomethingElseUseful;
- (void)abc_doSomethingUseful;
#end
and add an interface-only category for each class that conforms to SCNSceneRenderer declaring that it also conforms to your protocol:
// This also goes in a header file:
#interface SCNLayer (MyProtocolConformance) <MyProtocol>
#end
#interface SCNView (MyProtocolConformance) <MyProtocol>
#end
I don't think you can add category over a protocol, since protocol just defines interface not implementation. Whereas in category we need to implement as well.

Dependency injection with #protocol?

Can I use a #protocol for interfacing between classes? My main goal is to do some dependency injection like in Java (with interfaces and implements).
I've got the following classes: SignUpServiceImpl (which has an interface called SignUpService) and ServiceHelperImpl (interface is ServiceHelper).
I don't want to hard wire both implementations together so I use a #protocol in ServiceHelper which is implemented by ServiceHelperImpl. Then SignUpServiceImpl is initialized with ServiceHelper like this:
- (id)initWithHelper:(ServiceHelper *)myServiceHelper
Is what I'm trying to accomplish possible? It looks so much easier in Java....
An objc protocol is very similar to a Java interface.
The blocking point for you may be how you expect things are actually tied together -- or protocol syntax.
Declare a protocol:
#protocol ServiceHelperProtocol
- (void)help;
#end
Use it in a class:
#interface SomeClass : NSObject
- (id)initWithServiceHelper:(id<ServiceHelperProtocol>)inServiceHelper;
#end
#implementation SomeClass
- (id)initWithServiceHelper:(id<ServiceHelperProtocol>)inServiceHelper
{
self = [super init];
if (nil != self) {
[inServiceHelper help];
}
return self;
}
#end
MONHelper adopts the protocol:
#interface MONHelper : NSObject < ServiceHelperProtocol >
...
#end
#implementation MONHelper
- (void)help { NSLog(#"helping..."); }
#end
In use:
MONHelper * helper = [MONHelper new];
SomeClass * someClass = [[SomeClass alloc] initWithServiceHelper:helper];
...
To accept an object that conforms to a protocol, your init method should be like this:
- (id)initWithHelper:(id<ServiceHelper>)myServiceHelper
If you want to keep a number of different implementations behind a unified class interface, one way to do this in Objective-C is to create an abstract class SignUpService, then in the init method of SignUpService, instead of returning self you actually return a instance of the class that you want to implement it, so in your case, SignUpServiceImpl.
This is how certain class clusters in Cocoa like NSString work.
Let me know if you need more info.

Objective-C inheritance; calling overridden method from superclass?

I have an Objective-C class that has a method that is meant to be overridden, which is uses in a different method. Something like this:
#interface BaseClass
- (id)overrideMe;
- (void)doAwesomeThings;
#end
#implementation BaseClass
- (id)overrideMe {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (void)doAwesomeThings {
id stuff = [self overrideMe];
/* do stuff */
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
- (id)overrideMe {
/* Actually do things */
return <something>;
}
#end
However, when I create a SubClass and try to use it, it still calls overrideMe on the BaseClass and crashes due to doesNotRecognizeSelector:. (I'm not doing a [super overrideMe] or anything stupid like that).
Is there a way to get BaseClass to call the overridden overrideMe?
What you are describing here should work so your problem is likely elsewhere but we don't have enough information to help diagnose it.
From your description, I'd say either the instance you're messaging is not the class you think it is or you made some typo in your code when declaring the method names.
Run your application under gdb, add a symbolic breakpoint on objc_exception_throw, reproduce your problem. Once your process has stopped on the "doesNotRecognizeSelector" exception, print object description and it's class.
Or log it before calling -overrideMe:
NSLog(#"object: %# class: %#", obj, [obj class])
Write a category for BaseClass to override the method.
#interface BaseClass (MyCategory)
- (id) overrideMe;
#end
#implementation BaseClass (MyCategory)
- (id) overrideMe
{
/* Actually do things */
return <something>;
}
#end
Now all instances of BaseClass will respond to selector overrideMe with the new implementation.