Objective C: incompatible pointer types sending - objective-c

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.

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 equivalent to java anonymouse interface implementation

I hope the title is precise enough.
I was wondering, how I can pass a interface implementation to an object in objc language.
In java it would look like:
public interface MyInterface {
void onData();
}
The implementing class
public class ImplementMyInterface {
// ...
// other methods
///
void registerInterface(){
MyInterface myInterface = new MyInterface(){
#Override
public void onData(){
// process data here within the class
}
};
}
}
And in objc?
id myinterface.
How to implement it in the class?
Is there only the possibility to let the class inherit the interface?
Like
interface MyInterface : NSObject
and the implementing class
MyImplementingClass : MyInterface
Or is there another possibility?
Thank you in advance
Objective-C has anonymous functions (blocks), but it doesn't have anonymous classes. So, the only way to implement a protocol (which is the objective-c term for an interface) is to make some class conform to that protocol (using your terminology, make that class "inherit" from that protocol) and add a protocol implementation inside that class' implementation.
I was able to solve my problem.
I was only able to import the MyInterface header file in my ImplementMyInterface.m file, but rather in the ImplementMyInterface.h file.
So everything I could do was inside the ImplementMyInterface.m file.
// ImplementMyInterface.m
#import "MyInterface.h"
// inner class
#interface MyInternalInterface : NSObject<MyInterface>
#property (retain) ImplementMyInterface * implementation;
#end
// the actual class
#implementation ImplementMyInterface
MyInternalInterface * _internalInterface;
+(instancetype) build {
// construct myself
ImplementMyInterface * implementatMyInterface = [[ImplementMyInterface alloc] init];
// init inner class object
_internalInterface = [[MyInternalInterface alloc] init];
// register myself
[_internalInterface setImplementation:implementatMyInterface];
return implementatMyInterface;
}
- (NSString *) theActualData {
return #"The actual data";
}
// end of implementation class
#end
// implementation of inner class
#implementation MyInternalInterface
#synthesize implementation;
- (NSString *) onData {
if(implementation != nil)
return [implementation theActualData];
return #"";
}
// end of ImplementMyInterface.m

Abstract class in 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.

Issue understanding "Referring to Instance Variables" from Apple guide

I am trying to understand Referring to Instance Variables from Apple guide but having issue understudying this, Apple Doc says
...When the instance variable belongs to an object that’s not the receiver, the object’s type must be made explicit to the compiler through static typing. In referring to the instance variable of a statically typed object, the structure pointer operator (->) is used.
Suppose, for example, that the Sibling class declares a statically typed object, twin, as an instance variable:
#interface Sibling : NSObject
{
Sibling *twin;
int gender;
struct features *appearance;
}
As long as the instance variables of the statically typed object are within the scope of the class (as they are here because twin is typed to the same class), a Sibling method can set them directly:
- makeIdenticalTwin
{
if ( !twin )
{
twin = [[Sibling alloc] init];
twin->gender = gender;
twin->appearance = appearance;
}
return twin;
}
Referring to instance variable means, accessing the class instance vars
For example:
#interface ClassA : NSObject
{
int value;
}
- (void) setValue:(int) val;
#implementation ClassA
- (void) setValue:(int) val
{
//here you could access class a value variable like this
value = val;
}
Now accessing other classes variables
take for example this class
#interface ClassB : ClassA
{
ClassA aClass;
}
- (void) setValueInAClass:(int) val;
#implementation ClassB
- (void) setValueInAClass:(int) val
{
//class b could access variables from class a like this
aClass->value = val;
}
Please note that this is very un recommended to do, using the "->" breaks the encapsulation of class a, so dont in 99% of the cases referring to class variables using the "->" is a mistake

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.