Cocoa plugin pattern - objective-c

I have a plugin architecture for my desktop app. I've implemented it in a fairly standard way using Apple's code loading guide.
I have a single protocol which defines all the methods an instance of the plugin can or should respond to.
The only problem is this protocol defines around 80 methods. Only about 10 of these methods are compulsory and the rest are optional. Some plugins will implement all 80 methods, whereas others will only implement the basic 10.
The usual way for a plugin bundle to tell its host application which class to instantiate is via the NSPrincipalClass key in its Info.plist file. This is a single key so only a single class can be instantiated.
The plugin protocol is a single file and its expected that it will be used by this single class.
My question is: what is the best way of splitting up the functionality inside this single protocol into perhaps multiple protocols, whilst at the same time allowing the plugin writer to have a more flexible implementation?
Currently my existing plugins have the following in their principal class:
- (BOOL)respondsToSelector:(SEL)selector {
return [self forwardingTargetForSelector:selector] ? YES : NO;
}
- (id)forwardingTargetForSelector:(SEL)selector {
id target = nil;
if ([self.instanceOne respondsToSelector:selector]) {
target = self.instanceOne;
} else if ([self.instanceTwo respondsToSelector:selector]) {
target = self.instanceTwo;
} else if ([self.instanceThree respondsToSelector:selector]) {
target = self.instanceThree;
}
return target;
}
But rather than imposing it upon the plugin writer to define an ad hoc system like this, I would like the application's plugin framework to accomodate a more flexible solution.

If you can divide your 80 methods into sensible chunks of functionality, you could split them up into several protocols (FooProtcol, BarProtocol, etc.) and define optional properties that return references to objects that implement them in your primary protocol. For example:
#protocol PluginPrimaryProtocol <NSObject>
#required
/* ... */
#optional
#property (readonly) id<FooProtocol> fooDelegate;
#property (readonly) id<BarProtocol> barDelegate;
/* ... */
#end

Related

Static library callback

I have a static library that is currently sending responses using NSNotificationCenter. But I feel like delegates would be a better solution. The problem is how do I call the delegate methods when I do not know their headers yet. Im not sure how to implement the stuff that is not up to me when the library is in use.
So is there a good of allowing the user to create their own methods and the library calling them when they are needed?
Delegates are often communicated with by you declaring a protocol which specifies the set of callbacks.
#protocol MONImageGeneratorObserver <NSObject>
#required
// called when an image has been generated
- (void)generatedImageWasSavedToURL:(NSURL *)pURL;
- (void)imageGenerationDidComplete;
#end
Then you can tell your client the interface they must implement by specifying the protocol in your APIs:
- (void)setImageGeneratorObserver:(NSObject<MONImageGeneratorObserver>*)pObserver;
Another good way to accomplish this is provide a parameter which is a block. You'll usually want to copy that block when you receive it. Then you don't need to know anything about the client's code.
Your API should be very specific:
that you copy it
on which thread the block will be performed
#interface MONObject : NSObject
+ (void)performAsynchronousLoadWithSuccessfulCallback:(void(^)(void))pSuccess errorCallback:(void(^)(NSError *))pError;
#end
#implementation MONObject
+ (void)performAsynchronousLoadWithSuccessfulCallback:(void(^)(void))pSuccess errorCallback:(void(^)(NSError *))pError
{
if (random()%2) {
// load succeeded!
pSuccess();
}
else {
// load failed = =
NSError * e = ...;
pError(e);
}
}
#end
In both cases, you specify the interface and do not need to see their headers in your implementation. They can call their own methods in the block body or in their definitions of MONImageGeneratorObserver callbacks.

Prevent instantiation of readonly objects from framework

I am currently in the process of creating an objective c framework for iOS to help facilitate the interaction between an API and a developer. As part of this, I return various arrays of readonly objects that a developer can use to display information to the user. However, I would like to ensure that the objects displayed to the user come only from the framework and can not be instantiated by the developer using the framework.
My current implementation uses a custom constructor initializer that takes JSON from the api to instantiate itself. The only way that I am aware of accessing my custom constructor initializer is by putting its definition in the header file which makes it not only accessible to myself, but also the developer. I am aware that I can throw an inconsistency exception when the user tries to use the default constructor initializer, -(id)init;, but I can not stop them from creating their own JSON string and calling my custom constructor initializer.
Am I taking the correct approach to securing my private framework from interference from the developer using it? How else can I get around this to ensure the validity of data in these objects?
Source: Is it possible to make the -init method private in Objective-C?
You are correct that Objective-C doesn't allow for truly private methods by it's very nature, due to its dynamic dispatch system. However, assuming your question is not about true security, rather simply making it difficult to use the framework in an incorrect way, you have a few options.
A simple, common solution would be to put the declarations for methods you don't want to expose publicly in a category in a separate header file. You can still put these methods' implementations in the main implementation file for the class. So, a header with something like this:
// MyClass+Private.h
#interface MyClass (Private)
- (void)aPrivateMethod;
#end
Then, in your own source files where you need to access those private methods, you simply import MyClass+Private.h.
For a framework, you can set each header file to be Public or Private. Private headers will not be copied into the framework bundle, and therefore won't be visible to users of the Framework. You do this by opening the Utilities pane in Xcode (the right-side slide out pane), selecting the header in question, then choosing Private in the second column of the relevant row under "Target Membership".
Based on Andrew Madsen's solution, I ended up using was to have two different header files for each object; One that was public, and one that was private. The public header contains only the information needed by the developer to access the read only properties. Then my private header imports the public header and also contains a category with all the method calls I need to use within the SDK (including the initializer). I then import the private header into my implementation. The structure looks like this:
Public Header MyObject.h
#import <Foundation/Foundation.h>
#interface MyObject : NSObject
#property (nonatomic, retain, readonly) NSString *myValue;
#end
Private Header MyObject+Private.h
#import "MyObject.h"
#interface MyObject (Private)
+(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
-(id)initWithJSON:JSONString:(NSString*)JSONString
#end
Private Implementation MyObject.m
#import "MyObject+Private.h"
#implementation MyObject
#synthesize myValue = _myValue; //_myValue allows local access to readonly variable
- (id)init {
#throw [NSException exceptionWithName:NSInternalInconsistencyException reason:#"-init is not a valid initializer for the class MyObject" userInfo:nil];
return nil;
}
+(MyObject*)MyObjectFromJSONString:(NSString*)JSONString;
{
return [[MyObject alloc]initWithJSON:JSONString];
}
-(id)initWithJSON:JSONString:(NSString*)JSONString
{
self = [super init];
if(self){
//parse JSON
_myValue = JSONString;
}
return self;
}

What's the most robust and readable way of ensuring objects conform to a interface/protocol in Objective C?

I'm trying code to an interface (or a protocol in Objective C terminology), not an implementation.
It's critical that we check objects conform to protocol before calling methods on them to prevent crashes.
Three Ways
In compiler
At runtime
Both
Best Solution... Surely Number 1?
I thought the best way would be in the compiler:
Warnings ahoy if you screw up
Eliminates conformsToProtocol:/respondsToSelector: boilerplate
At runtime it's too late if you made a mistake - the best you can do is not execute the code/show an error
But I see a lot of code that's doing it at runtime. Why?
Is it a readability issue - needing id <Protocol> everywhere?
My Question
What's the most robust and readable way of ensuring objects conform to a interface/protocol?
Code
1. Checking In Compiler
#interface ReportController : NSObject {
id <ReportGenerator> generator;
id <ReportSender> sender;
id report;
}
#implementation ReportController
-(id)initWithReportGenerator:(id <ReportGenerator>)generator_
reportSender:(id <ReportSender>)sender_ {
// Usual init stuff
generator = generator_;
sender = sender_;
return self;
}
-(void)generateAndSend {
report = [generator generate];
[sender sendReport:report];
}
#end
2. Checking At Runtime
#interface ReportController : NSObject {
id generator;
id sender;
id report;
}
#implementation ReportController
-(id)initWithReportGenerator:(id)generator_
reportSender:(id)sender_ {
// Usual init stuff
generator = generator_;
sender = sender_;
return self;
}
-(void)generateAndSend {
if ([generator conformsToProtocol:#protocol(ReportGenerator)] &&
[sender conformsToProtocol:#protocol(ReportSender)]) {
report = [generator generate];
[sender sendReport:report];
} else {
[NSException raise:NSInternalInconsistencyException format:#"Objects didn't respond to protocols..."];
}
}
#end
You should use both. Consider e.g.:
#protocol Proto
- (void)someFunction;
#end
#interface C : NSObject
- (void)proto:(id<Proto>)p;
#end
// ...
NSString *s = #"moo";
id i = s;
C *c = [[C alloc] init];
[c proto:s]; // warns
[c proto:i]; // doesn't warn
Objective-C and Cocoa are too dynamic to generally check such things at compile time (NSProxy standins, classes dynamically adding methods and protocols, ...).
It is nice to catch as many of such errors at compile-time as possible, but that alone is not sufficient.
As long as you don't use plain id as the type, the compiler will at least warn you if you make a mistake at compile time. So you should be fine with your code example #1.
Of course, sometimes you might be forced to work with an id object that you get from a subsystem that is not under your control. In such cases you can cast the object back to the type you think it has (e.g. id <ReportGenerator>), but you are usually better off if you perform a runtime check first. Better be safe than sorry...
On a final note: If your protocol has optional parts (declared with the #optional keyword), then for those parts you will obviously be able to do runtime checks only. The #required keyword mentioned by apurv is necessary only if you want to be explicit in your protocol declaration (a protocol's parts are required by default), or if you mix optional and required parts.
You should create methods with #required type in protocol.
So whatever class wants to take a contract with this protocol, will must have to implement those methods.
It will definitely make sure that the required methods are available at compile time only.

ObjC: must I specify the inheritance in the header file?

Common examples for a ObjC object are like this (for the header file):
#interface A: B {
int x;
int y;
}
#end
Is it possible to avoid the inheritance specification (i.e. B here) in the header file?
In my case, the framework A defines that class A and another (sub-)framework B defines the class B (which is a subclass of NSView). A links to B. In my application, I link to A and I don't need to know anything about B except that it is a subclass of NSView. And I want to avoid to link to B. But if B is in the header file, I think I cannot avoid it, that's why I was asking about how to avoid it.
No. You have to specify the superclass for any subclass. May I ask why you would want to do something like this?
Your application will need the code for B, therefore you must either link to B's framework, or compile the B framework into your A framework. Either way, you cannot use an instance of A without the code for B, and you must include B's header in your A header.
no.
you must often work around this with a class cluster, hold a private implementation, or create an object factory. then you can minimize the dependencies across modules.
you'll still ultimately need to link to the sub library at some stage if you intend to use it (e.g. create an instance of).
Update - Demonstrate Private Implementations
Private implementations can be entirely opaque. If you do expose them, here are two ways to implement private implementations which are visible to clients:
via protocol:
// MONDrawProtocol.h
// zero linkage required
// needs to be visible to adopt
// may be forwarded
#protocol MONDrawProtocol
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#protocol MONDrawProtocol;
#interface MONView : NSView
{
NSObject<MONDrawProtocol>* drawer;
}
#end
// MONView.m
#include "MONDrawProtocol.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
via base:
// MONDrawer.h
// base needs to be visible to subclass and types which use MONDrawer
// may be forwarded
#interface MONDrawer : NSObject
- (void)drawView:(NSView *)view inRect:(NSRect)rect;
#end
// MONView.h
#class MONDrawer;
#interface MONView : NSView
{
MONDrawer * drawer;
}
#end
// MONView.m
#include "MONDrawer.h"
#implementation MONView
- (void)drawRect:(NSRect)rect
{
[self.drawer drawView:self inRect:rect];
}
#end
If you don't specify a superclass in the interface, then your class is a root class. This means it doesn't inherit from any other class, so it is responsible for providing its own implementation of the required methods (most of those defined by the NSObject class and protocol). Since this is not a simple task, it is highly encouraged that you inherit from some other class which provides these methods.
Yes you can, with that you will also lost default implementations of alloc, init, etc. Which makes you write your own alloc, init and other stuffs which was there in NSObject
can't you just include a mock version of the class you're inheriting from A's header itself? Not sure if that will cause problems, but it would allow you to clean up your linking requrirements a bit. B-new could then be a category of B'Original
I have one solution now. Instead of providing the class, I just provide a function like this:
NSView* allocA();
Internally in the framework A, A is a subclass of B.

iPhone SDK: Accessing methods in other classes

In my iPhone application I have multiple class files, I have my main application's class files, then I have my UIView class files. I have a simple -(void) method declared in my UIView class files, how can I access it from my main applications class files?
A bit more detail: In my application a video is played, when this video finishes playing a notification is sent and actions are preformed, which I have already successfully set up, however when the movie finishes I would like a method declared in another class file to be preformed. If the method was declared in the same class file I would simply use this code: [self mySimpleVoidMethod]; But obviously this doesn't work If the method is declared in a different class file. I believe it is possible to access a method declared in a different class file, but I just haven't got a clue about how to do it. Sorry if I'm using completely incorrect terms to name things. But I am relatively new to programming all together.
You've got a couple of options, depending on your setup. Here are a few:
1) Add a reference to the class with the function (the callee) as a property in the caller's class:
Caller.h
#interface Caller : SomeObject {
Callee *myCallee;
...
}
#property(nonatomic, retain) Callee *myCallee;
Caller.m
#synthesize myCallee;
-(void)someAction {
[myCallee doSomething];
}
Something that sets up Caller after initializing both classes:
caller.myCallee = callee;
2) Use another notification event, like it looks like you already know how to do.
3) Use a protocol if you've got a bunch of different classes that Caller might need to call that all support the same method:
DoesSomething.h
#protocol DoesSomething
-(void)doSomething;
#end
Callee.h
#interface Callee : NSObject<DoesSomething> { // NSObject or whatever you're using...
...
}
-(void)doSomething;
Caller.h
#interface Caller : SomeObject {
id<DoesSomething> *myCallee;
...
}
#property(nonatomic, retain) id<DoesSomething> *myCallee;
... Then as per example 1.
4) Use performSelector to send a message to the class.
Caller.h
#interface Caller : NSObject {
SEL action;
id callee;
}
-(void)setupCallbackFor:(id)target action:(SEL)callback;
Caller.m
-(void)setupCallbackFor:(id)target action:(SEL)callback {
callee = target;
action = callback;
}
-(void)someAction {
if([callee respondsToSelector:action]) {
[callee performSelector:action];
}
I'm sure there are other ways, and there are pros and cons to each of these, but something in there should fit your needs and/or give you enough to scan the documentation to fill in any gaps...
I did a blog post a few weeks ago that outlines one way to do this. It is similar to the previous answers, and includes some sample code you can download and look at. It is based on using table view controllers, but you should be able to adapt the ideas to your application without too much difficulty.
Passing values and messages between views on iPhone
You'll need an instance of the other class, accessible from the code that runs when the movie finishes. Often, this is accomplished by storing an instance of the other class as a field in the class, set either via a "setter", or during construction. You could also use key-value observing, watching a key representing the playstate of the movie; an instance of the other class can register to observe the changes to this key.
Specifically for patterns using UIView, your UIViewController for the view will have access to it (through the view method). If your "main application's class files" have a pointer to the controller - which they probably will, setup via Interface Builder - then that's an easy way to get to a UIView instance.