Dependency injection with #protocol? - objective-c

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.

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 protocol generics

Can Objective-C protocol be generic?
Following this tutorial, I'm basically looking for something like that:
#protocol ItemsStore<__covariant ObjectType> <NSObject>
-(NSArray <ObjectType> *)items;
#end
Which is a generic protocol for some ObjectType that "implements" ("inherits") another protocol NSObject
As #rmaddy suggested, and as referred to this questions, it is NOT possible.
Shame, moving to Swift then...
Maybe you could just redefine it as generic in the interface.
#protocol ItemsStore <NSObject>
- (NSArray *)items;
#end
#interface MyItemsStore<ObjectType> : NSObject <ItemsStore>
- (NSArray <ObjectType> *)items;
#end
This seems an unlikely scenario though. You might be better just defining the type of the items in each subclass. Like what Apple do with NSFetchRequest in their core data model generation.
Probably, this question has exactly the same source problem as mine. Well, the idea of the design is great but doesn't work with ObjC. I also was wondering about that. I thought it could work some way like that:
#protocol Prototype<__covariant OtherProtocolOrClass> <NSObject>
/// Construct an object of the desired class or protocol
#property (nonatomic, nonnull, readonly) <OtherProtocolOrClass> objectFromPrototype;
#end
(I have not tested #protocol Prototype <NSObject,__covariant OtherProtocolOrClass> yet, but think it will fail.)
Another object in my framework (it is a collection) states, it can auto-construct an NSArray<ObjectType>* of an object type, if there is a Prototype that returns instances, like this:
#interface ValueProto : NSObject <Prototype<id<Value>>>
#end
#implementation ValueProto
-(id<Value>)objectFromPrototype {
return [Value new];
}
#end
Im my dreams, the collection was constructed like this:
MyCollection<id<Value>>* const collection = [MyCollection new];
collection.prototype = [ValuesProto new];
And if you then access the collection's property, your array of id<Value> objects is constructed on the fly:
-(NSArray<id<Value>>*)values {
NSArray*const sourceCollection = ...
NSMutableArray<id<Value>>* const result = [NSMutableArray arrayWithCapacity:sourceCollection.count];
for (id o in sourceCollection) {
id<Value> v = self.prototype.objectFromPrototype;
v.content = o;
[result addObject:v];
}
return result;
}
Instead one of my class' objects must be the prototype itself:
-(id)objectFromPrototype {
return [self.class new];
}
That clashes with my so-called 'Injector', which constructs and returns objects by protocols instead of classes.
If any Apple engineer is reading this:
Please, provide protocol covariants for ObjC. It's not yet dead! :-)
Why not use generic abstract class?
#interface AbstractItemStore <__covariant ObjectType> : NSObject
- (NSArray<ObjectType> *)items;
#end
#implementation AbstractItemStore
- (NSArray<id> *)items {
NSParameterAssert("Not implemented!");
return nil;
}
#end

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.

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.

What does < > mean / represent in a class interface?

I am sure I have read this somewhere, Can anyone tell me what the < > represent in the following interface?
#interface GameFinder : NSObject <NSNetServiceBrowserDelegate>
#end
is NSObject adopting <NSNetServiceBrowserDelegate> ?
EDIT
One thing that is confusing me ...
in the example I have.The interface shows NSNetServiceBrowserDelegate
#interface ITunesFinder : NSObject <NSNetServiceBrowserDelegate>
#end
but the implementation shows netServiceBrowser, are these one in the same?
#implementation ITunesFinder
-(void) netServiceBrowser: (NSNetServiceBrowser *) browser
didFindService: (NSNetService *) service
moreComing: (BOOL) moreComing {
gary
The angle brackets denote Protocols that this class meets. There are details on Protocols int the Objective-C Wikipedia article that may help clear up some things for you. Protocols contain both required and optional routines that your class could supply. In the latter case if the routine is not implemented by your class a default implementation/behavior is used instead.
< > represent a protocol (or list of protocols) to which a class conforms. An Objective-C protocol is like an interface in Java: it's a list of methods that the conforming class must implement.
The angle brackets in an interface declaration denote the list of Objective-C protocols that the interface implements. In this case, that GameFinder conforms to the NSNetServiceBrowserDelegate protocol. The Objective-C Language Reference has a full section on protocols (and is a reference you should keep handy in general while learning Objective-C). Basically, a Protocol is an interface that describes the methods a class must implement to conform to that protocol. Classe interfaces may declare, using the angle bracket notation, that they conform to (implement) a protocol. The compiler will check protocol conformance if you provide protocol information in type declarations:
#interface Foo <Bar>
...
- (void)methodRequiringBar:(id<Bar>)arg;
#end
#interface Foo2 <Baz>
...
#end
id<Bar> v = [[Foo alloc] init]; //OK
id<Baz> v = [[Foo alloc] init]; //warning
[v methodRequiringBar:[[Foo2 alloc] init]]; //warning
The compiler will also warn you if a class interface declares conformance to a protocol but not all of the required methods in that protocol are implemented by the class' implementation:
#protocol Bar
#required
- (void)requiredMethod;
#optional
- (void)optionalMethod;
#end
#interface Foo <Bar>
...
#end
#implementation Foo
- (void)optionalMethod {
...
}
#end
will give a warning that the Bar protocol is not fully implemented.
NSNetServiceBrowser is a class. NSNetServiceBrowserDelegate is a protocol specifying what methods an NSNetServiceBrowser's delegate must implement.