Can I use an application as a library (Mac, Objective-c)? - objective-c

Is there a way to load classes from a mac app, and use them in a different mac app?
I'd like to make an Automator action that accesses some of the classes in my mac app, and this seems like the sort of way I'd ideally do it (means you have to have bought my app to use the Automator action, etc.)

Depending on what you want to do (I'm not quite clear), a Service might do the trick for you. You make a helper app which can pass data back and forth with your app, using a shared pasteboard. You can get a fairly wide range of action, because you can pass any object that conforms to the NSPasteboardWriting and NSPasteboardReading protocols; as it says there in the docs, NSString, NSAttributedString, NSURL, NSColor, NSSound, and NSImage are already available for you, and of course you can write a custom class that suits your needs exactly.

Have you tried creating a stand-alone Automator plugin project, or tried adding an Automator bundle target to your application's project?
I'm assuming that you want to create Automator actions for your main app, but are unclear how you get these actions to interact with your application (or with the classes present in your application).
There are 3 basic types of Automator actions: AppleScript-based, shell-script based, and Objective-C based. You'll most likely want to make yours Objective-C-based, which will allow you to easily incorporate other Objective-C code from your main application into the action itself (see Implementing an Objective-C Action). (Note that by default, when you add a new target for an automator bundle, it's an AMAppleScriptAction type).
To see how an Objective-C automator action is set up compared to an AppleScript-based action, you might want to try creating a separate standalone project.
Let's say your app is document-based, and uses the KWDocument class, which exposes a method named -duplicateObjects:(NSArray *)objects toDocument:(KWDocument *)destDocument;. You also have a KWRegistrationManager that knows whether your app is registered or not. And let's say you want to create an automator action that's called "Duplicate Objects to Document". The action will be implemented in KWDuplicateObjectsToDocument, which is as a subclass of AMBundleAction. In the Info.plist for Duplicate Objects to Document.action, the NSPrincipalClass will be KWDuplicateObjectsToDocument.
KWDuplicateObjectsToDocument.h will look something like:
#import <Cocoa/Cocoa.h>
#import <Automator/AMBundleAction.h>
#interface KWDuplicateObjectsToDocument : AMBundleAction {
}
- (id)runWithInput:(id)input fromAction:(AMAction *)anAction
error:(NSDictionary **)errorInfo;
#end
And your KWDuplicateObjectsToDocument.m will look something like this:
#import "KWDuplicateObjectsToDocument.h"
#import "KWDocument.h"
#import "KWRegistrationManager.h"
#implementation KWDuplicateObjectsToDocument
- (id)runWithInput:(id)input fromAction:(AMAction *)anAction
error:(NSDictionary **)errorInfo {
if (![[KWRegistrationManager defaultManager] isRegistered]) {
return nil;
}
// eventually you'll call
// duplicateObjects:toDocument:
return input;
}
#end
You'll need to make sure that the necessary classes you use (such as KWRegistrationManager, KWDocument, etc.) are compiled and included as part of the build process for this bundle.

Basically, no: you cannot link with an executable.
An application binary is in a specific format.
And that format is different from the static or shared library format.
It means you won't be able to load any code parts from an application binary, as you would with a library.

Take a look at distributed objects. Your application could vend one or more objects that your Automator action could use. I've never tried it with Automator, but it's a very elegant system that hasn't gotten a lot of attention in recent years. I think it's definitely worth a look.
One cool aspect of distributed objects is that the application could be running on the same computer if you wish, but it could just as easily be running on a different computer, perhaps even one that's very far away.

You could make certain behavior from you app accessible via Applescript, but accessing the the actual classes is not possible in the way I think you mean. I get the impression that you mean accessing the classes loaded into the memory of your running app. This is not possible on OS X (or any UNIX-like system). Applications run at the user level. Processess at the user level are not able to read memory from other processes. The components of the OS that need to do this sort of thing run at kernel level.
If you are just trying to reuse the code, you could build the parts you want to share into a static library, and others could link against it and share your code.
EDIT:
From NSGod's answer it seems that you can use the same approach that makes it accessible via Applescript and make it accessible via Obj-C. That looks pretty cool.

Related

Header files without implementation

I'm working on a open source project, which consist on a framework for iOS devices, and one of the methods is not working as I expected. I tried to search for the implementation of the method, but all I found was a a header file and the method declaration; I didn't find the implementation anywhere. Neither did I find the .m file corresponding to that class.
So I have some questions:
How can a class exist without it's implementation and still its methods perform certain operations?
What is the purpose of writing this kind of classes.
In this kind of situations where should be the methods implemented?
Note
The open source project is FastPdfKit and the method is wholeTextForPage:
Well, those methods are somewhere, so it's not that they don't exist, you just can't see them.
Try for example to open UITableView.h, you can see the methods definition, but not the implementation. The implementation is hidden in the library, but you can't see it.
In a nutshell, developers do this to hide the details of the implementation of a class to other users. You just receive a header that tells you which methods you can use, and how, but the details about how are they implemented are hidden for you.
For example, Apple doesn't want you to see how they implemented UITableView, but they want you to know how you can use it.
Here you can find a tutorial about how to create a library for Objective-C:
Creating Static Libraries for Objective-C

Is overriding Objective-C framework methods ever a good idea?

ObjC has a very unique way of overriding methods. Specifically, that you can override functions in OSX's own framework. Via "categories" or "Swizzling". You can even override "buried" functions only used internally.
Can someone provide me with an example where there was a good reason to do this? Something you would use in released commercial software and not just some hacked up tool for internal use?
For example, maybe you wanted to improve on some built in method, or maybe there was a bug in a framework method you wanted to fix.
Also, can you explain why this can best be done with features in ObjC, and not in C++ / Java and the like. I mean, I've heard of the ability to load a C library, but allow certain functions to be replaced, with functions of the same name that were previously loaded. How is ObjC better at modifying library behaviour than that?
If you're extending the question from mere swizzling to actual library modification then I can think of useful examples.
As of iOS 5, NSURLConnection provides sendAsynchronousRequest:queue:completionHandler:, which is a block (/closure) driven way to perform an asynchronous load from any resource identifiable with a URL (local or remote). It's a very useful way to be able to proceed as it makes your code cleaner and smaller than the classical delegate alternative and is much more likely to keep the related parts of your code close to one another.
That method isn't supplied in iOS 4. So what I've done in my project is that, when the application is launched (via a suitable + (void)load), I check whether the method is defined. If not I patch an implementation of it onto the class. Henceforth every other part of the program can be written to the iOS 5 specification without performing any sort of version or availability check exactly as if I was targeting iOS 5 only, except that it'll also run on iOS 4.
In Java or C++ I guess the same sort of thing would be achieved by creating your own class to issue URL connections that performs a runtime check each time it is called. That's a worse solution because it's more difficult to step back from. This way around if I decide one day to support iOS 5 only I simply delete the source file that adds my implementation of sendAsynchronousRequest:.... Nothing else changes.
As for method swizzling, the only times I see it suggested are where somebody wants to change the functionality of an existing class and doesn't have access to the code in which the class is created. So you're usually talking about trying to modify logically opaque code from the outside by making assumptions about its implementation. I wouldn't really support that as an idea on any language. I guess it gets recommended more in Objective-C because Apple are more prone to making things opaque (see, e.g. every app that wanted to show a customised camera view prior to iOS 3.1, every app that wanted to perform custom processing on camera input prior to iOS 4.0, etc), rather than because it's a good idea in Objective-C. It isn't.
EDIT: so, in further exposition — I can't post full code because I wrote it as part of my job, but I have a class named NSURLConnectionAsyncForiOS4 with an implementation of sendAsynchronousRequest:queue:completionHandler:. That implementation is actually quite trivial, just dispatching an operation to the nominated queue that does a synchronous load via the old sendSynchronousRequest:... interface and then posts the results from that on to the handler.
That class has a + (void)load, which is the class method you add to a class that will be issued immediately after that class has been loaded into memory, effectively as a global constructor for the metaclass and with all the usual caveats.
In my +load I use the Objective-C runtime directly via its C interface to check whether sendAsynchronousRequest:... is defined on NSURLConnection. If it isn't then I add my implementation to NSURLConnection, so from henceforth it is defined. This explicitly isn't swizzling — I'm not adjusting the existing implementation of anything, I'm just adding a user-supplied implementation of something if Apple's isn't available. Relevant runtime calls are objc_getClass, class_getClassMethod and class_addMethod.
In the rest of the code, whenever I want to perform an asynchronous URL connection I just write e.g.
[NSURLConnection sendAsynchronousRequest:request
queue:[self anyBackgroundOperationQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *blockError)
{
if(blockError)
{
// oh dear; was it fatal?
}
if(data)
{
// hooray! You know, unless this was an HTTP request, in
// which case I should check the response code, etc.
}
/* etc */
}
So the rest of my code is just written to the iOS 5 API and neither knows nor cares that I have a shim somewhere else to provide that one microscopic part of the iOS 5 changes on iOS 4. And, as I say, when I stop supporting iOS 4 I'll just delete the shim from the project and all the rest of my code will continue not to know or to care.
I had similar code to supply an alternative partial implementation of NSJSONSerialization (which dynamically created a new class in the runtime and copied methods to it); the one adjustment you need to make is that references to NSJSONSerialization elsewhere will be resolved once at load time by the linker, which you don't really want. So I added a quick #define of NSJSONSerialization to NSClassFromString(#"NSJSONSerialization") in my precompiled header. Which is less functionally neat but a similar line of action in terms of finding a way to keep iOS 4 support for the time being while just writing the rest of the project to the iOS 5 standards.
There are both good and bad cases. Since you didn't mention anything in particular these examples will be all-over-the-place.
It's perfectly normal (good idea) to override framework methods when subclassing:
When subclassing NSView (from the AppKit.framework), it's expected that you override drawRect:(NSRect). It's the mechanism used for drawing views.
When creating a custom NSMenu, you could override insertItemWithTitle:action:keyEquivalent:atIndex: and any other methods...
The main thing when subclassing is whether or not your behaviour completes re-defines the old behaviour... or extends it (in which case your override eventually calls [super ...];)
That said, however, you should always stand clear of using (and overriding) any private API methods (those normally have an underscore prefix in their name). This is a bad idea.
You also should not override existing methods via categories. That's also bad. It has undefined behaviour.
If you're talking about categories, you don't override methods with them (because there is no way to call original method, like calling super when subclassing), but only completely replace with your own ones, which makes the whole idea mostly pointless. Categories are only useful for safely extending functionality, and that's the only use I have even seen (and which is a very good, an excellent idea), although indeed they can be used for dangerous things.
If you mean overriding by subclassing, that is not unique. But in Obj-C you can override everything, even private undocumented methods, not just what was declared 'overridable' like in other languages. Personally, I think it's nice, as I remember in Delphi and C++ I used to “hack” access to private and protected members to workaround an internal bug in framework. This is not a good idea, but at some moments it can be a life saver.
There is also method swizzling, but that's not standard language feature, that's a hack. Hacking undocumented internals is rarely a good idea.
And regarding “how can you explain why this can best be done with features in ObjC”, the answer is simple — Obj-C is dynamic, and this freedom is common to almost all dynamic languages (Javascript, Python, Ruby, Io, a lot more). Unless artificially disabled, every dynamic language has it.
Refer to the wikipedia page on dynamic languages for longer explanation and more examples. For example, an even more miraculous things possible in Obj-C and other dynamic languages is that an object can change it's type (class) in place, without recreation.

Creating an Objective-C API

I have never made an API in objective-c, and need to do this now.
The "idea" is that I build an API which can be implemented into other applications. Much like Flurry, only for other purposes.
When starting the API, an username, password and mode should be entered. The mode should either be LIVE or BETA (I guess this should be an NSString(?)), then afterwards is should be fine with [MyAPI doSomething:withThisObject]; ect.
So to start it [MyAPI username:#"Username" password:#"Password" mode:#"BETA"];
Can anyone help me out with some tutorials and pointer on how to learn this best?
It sounds like what you want to do is build a static library. This is a compiled .a file containing object code that you'll distribute to a client along with a header file containing the interface. This post is a little outdated but has some good starting points. Or, if you don't mind giving away your source code, you could just deliver a collection of source files to your client.
In terms of developing the API itself, it should be very similar to the way you'd design interfaces and implementations of Objective-C objects in your own apps. You'll have a MyAPI class with functions for initialization, destruction, and all the functionality you want. You could also have multiple classes with different functionality if the interface is complex. Because you've capitalized MyAPI in your code snippet, it looks like you want to use it by calling the class rather than an instance of the class - which is a great strategy if you think you'll only ever need one instance. To accomplish this you can use the singleton pattern.
Because you've used a username and password, I imagine your API will interface with the web internally. I've found parsing JSON to be very straightforward in Objective-C - it's easy to send requests and get information from a server.
Personally I would use an enum of unsigned ints rather than a NSString just because it simplifies comparisons and such. So you could do something like:
enum {
MYAPI_MODE_BETA,
MYAPI_MODE_LIVE,
NUM_MYAPI_MODES
};
And then call:
[MyAPI username:#"Username" password:#"Password" mode:MYAPI_MODE_BETA];
Also makes it easy to check if they've supplied a valid mode. (Must be less than NUM_MYAPI_MODES.)
Good luck!

How can I implement the service locator pattern in Cocoa Touch across multiple projects?

This is a problem which has been bugging me for a while now. I'm still pretty new with some of these patterns so you'll have to forgive me (and correct me) if I use any of the terms incorrectly.
My Methodology
I've created a game engine. All of the objects in my game engine use inversion of control to get dependencies. These dependencies all implement protocols and are never accessed directly in the project, other than during the bootstrapping phase. In order to get these objects, I have the concept of a service locator. The service locator's job is to locate an object which conforms to a specific protocol and return it. It's a lot like a factory, but it should handle the dependencies as well.
In order to provide the services to the service locator, I have what I call service specifiers. The service locator knows about all of the service specifiers in the project, and when an object is requested, attempts to get an instance of an object conforming to the provided protocol from each of them. This object is then returned to the caller. What's cool about this set up is the service specifier also knows about a service locator, so if it has any dependencies, it just asks the service locator for those specific dependencies.
To give an example, I have an object called HighScoreManager. HighScoreManager implements the PHighScoreManager protocol. At any time if an instance of PHighScoreManager is required, it can be retrieved by calling:
id<PHighScoreManager> highScoreManager = [ServiceLocator resolve: #protocol(PHighScoreManager)];
Thus, inversion of control. However, most of the time it isn't even necessary to do this, because most classes are located in a service specifier, if one required PHighScoreManager as a dependency, then it is retrieved through the service locator. Thus, I have a nice flat approach to inversion of control.
My Problem
Because I want the code from my game engine to be shared, I have it compiled as a static library. This works awesome for everything else, but seems to get a little tricky with the service locator. The problem is some services change on a game to game basis. In my above example, a score in one game might be a time and in another it might be points. Thus, HighScoreManager depends on an instance of PHighScoreCreator, which tells it how to create a PScore objecct.
In order to provide PHighScoreCreator to HighScoreManager, I need to have a service specifier for my game. The only way I could think of to accomplish this was to use the Cocoa version of reflections. After digging around, I found out classes were discoverable through NSBundle, but it seems there's no way to get the current bundle. Thus, if I want to be able to search out my service specifiers, I would have to compile my game logic into its own bundle, and then have the engine search out this bundle and load it. In order to do this I'd have to create a third project to house both the engine code and the game logic bundle, when in reality I'd like to just have a game project which used the engine static library.
My Real Question
So after all of that, my question is
Is there a better way to do what I'm trying to accomplish in Cocoa Touch, or
Is there a way to discover classes which conform to my service specifier protocol from the main bundle?
Thanks for the help and taking the time to read the question.
-helixed
Have a look at:
+[NSBundle mainBundle];
+[NSBundle bundleForClass:];
+[NSBundle bundleWithIdentifier:];
+[NSBundle allBundles];
+[NSBundle allFrameworks];
These allow you to interact programmatically with the various bundles at runtime. Once you have a bundle to work with there are a number of strategies you could employ to find the specific class(es) you are looking for. For example:
Retrieve the bundle identifier — this will be an NSString like #"com.example.GameEngineClient".
Transform it into a legal Objective-C class name by stripping everything before the last dot, or replacing all the dots with underscores, or whatever, and then appending a predefined protocol name. Your protocol from above, for instance, might result in a string like #"GameEngineClient_PHighScoreManager".
Get the bundle's designated class for your protocol using NSClassFromString().
Now you can create an instance of the class provided by the bundle author, that implements whatever protocol you have specified.
The Objective-C runtime is a beautiful thing!
Sounds like you need to use the functions of the Objective-C runtime. First you can get a list of all available classes via objc_getClassList. Then you can iterate over all the classes and check if they conform to your protocol with class_conformsToProtocol. You shouldn’t use +conformsToProtocol: messages here, since there are classes in the runtime that don’t support this selector.

Load class file dynamically (Objective-C)

In an effort to create a sandbox for CoreGraphics development (which currently consists of performing multiple build and run attempts in order to achieve the desired effect), I was curious if there was a way to dynamically load a class file at runtime.
Much like Java's class-loader ability, I was hoping to use NSBundle or something similar to dynamically load a class into memory.
The idea would be to setup a sandbox project and only have to compile then dynamically reload the class, without having to stop and re-run the host application.
NSBundle can be used to load code dynamically. Have a look at -load.
I don't get why you want to reload such a bundle. (You can through -unload and -load.) It feels wrong, the only code that gets called again is +load and +initialize. You should just need to create a new instance of your class.