Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add docs

  • Loading branch information...
commit b1358df4d184d72f63aab539a88b77b714279b5a 1 parent 2b7c631
Samuel Sutch authored
60 CocoaDeferred/Source/DeferredKit/DKCallback.h
@@ -7,11 +7,31 @@
7 7
8 8 #import <Foundation/Foundation.h>
9 9
  10 +/**
  11 + * Shorthand for [DKCallback fromSelector:]
  12 + */
10 13 #define callbackS(sel) [DKCallback fromSelector:@selector(sel)]
  14 +/**
  15 + * Shorthand for [DKCallback fromSelector:target:]
  16 + */
11 17 #define callbackTS(tgt, sel) [DKCallback fromSelector:@selector(sel) target:tgt]
  18 +/**
  19 + * Shorthand for [DKCallback fromPointer:]
  20 + */
12 21 #define callbackP(fp) [DKCallback fromPointer:fp]
  22 +/**
  23 + * Shorthand for [DKCallback fromInvocation:parameterIndex:]
  24 + */
13 25 #define callbackI(inv, i) [DKCallback fromInvocation:inv parameterIndex:i]
14 26
  27 +
  28 +/**
  29 + * DKCallback (protocol)
  30 + *
  31 + * Provides a unified function object. Callbacks can be made any
  32 + * target but must take a single <code>(id)</code> argument and return
  33 + * an <code>(id)</code>.
  34 + */
15 35 @protocol DKCallback <NSObject>
16 36
17 37 - (id):(id)arg;
@@ -20,13 +40,53 @@
20 40
21 41 typedef id (*dkCallback)(id);
22 42
  43 +
  44 +/**
  45 + * DKCallback (interface)
  46 + *
  47 + * Provides implementations of DKCallback for.
  48 + * <pre>
  49 + * -[arg selector]
  50 + * -[target selector:arg]
  51 + * functionPointer(arg)
  52 + * NSInvocation objects
  53 + * </pre>
  54 + */
23 55 @interface DKCallback : NSObject <DKCallback>
24 56
  57 +/**
  58 + * Returns a DKCallback which will get it's result from performing <code>selector</code>
  59 + * on the argument it's called with.
  60 + */
25 61 + (DKCallback *)fromSelector:(SEL)s;
  62 +
  63 +/**
  64 + * Returns a DKCallback that will get it's result from
  65 + * performing <code>selector</code> on <code>target</code>. <code>selector</code>
  66 + * must always take exactly one <code>id</code> arg and return <code>id</code>.
  67 + */
26 68 + (DKCallback *)fromSelector:(SEL)s target:(NSObject *)target;
  69 +
  70 +/**
  71 + * Returns a DKCallback from a function pointer. It must have the signature
  72 + * <code>id f(id arg) { }</code>
  73 + */
27 74 + (DKCallback *)fromPointer:(dkCallback)f;
  75 +
  76 +/**
  77 + * Returns a DKCallback from an NSInvocation parameter index must always be at least 2
  78 + * to accomidate for <code>_cmd</code> and <code>self</code>.
  79 + */
28 80 + (DKCallback *)fromInvocation:(NSInvocation *)inv parameterIndex:(NSUInteger)i;
  81 +
  82 +/**
  83 + * Returns a DKCallback that calls <code>other</code> with the result of <code>self</code>
  84 + */
29 85 - (DKCallback *)andThen:(DKCallback *)other;
  86 +
  87 +/**
  88 + * Returns a DKCallback that calls <code>self</code> with the result of <code>other</code>
  89 + */
30 90 - (DKCallback *)composeWith:(DKCallback *)other;
31 91
32 92 @end
40 CocoaDeferred/Source/DeferredKit/DKDeferred+JSON.h
@@ -11,17 +11,32 @@
11 11
12 12 @interface DKDeferred (JSONAdditions)
13 13
  14 +/**
  15 + * Returns a Deferred which will callback with the native representation
  16 + * of the JSON document at <code>aUrl</code>
  17 + */
14 18 + (id)loadJSONDoc:(NSString *)aUrl;
  19 +
  20 +/**
  21 + * Returns a DKJSONServiceProxy which you can use to transparently call
  22 + * JSON-RPC methods on your web service.
  23 + */
15 24 + (id)jsonService:(NSString *)aUrl;
  25 +
  26 +/**
  27 + * Returns a DKJSONServiceProxy which you can use to transparently call
  28 + * JSON-RPC methods on your web service located at <code>aUrl</code>. It will be
  29 + * preconfigured to use <code>serviceName</code> as the method.
  30 + */
16 31 + (id)jsonService:(NSString *)aUrl name:(NSString *)serviceName;
17 32
18 33 @end
19 34
20 35 /**
21   - * = DKJSONServiceProxy =
22   - *
  36 + * DKJSONServiceProxy
  37 + *
23 38 * Adds some syntatic sugar to interacting with a JSON-RPC Service
24   - *
  39 + * <pre>
25 40 * id _fromJSONResponse(id result) { // result will be an NSDictionary or NSArray
26 41 * // do some stuff
27 42 * return nil;
@@ -34,8 +49,9 @@
34 49 * }
35 50 *
36 51 * id service = [DKDeferred jsonService:@"http://url.net/j" name:@""];
37   - * [[[service someNamespace] someMethod]
  52 + * [[[service someNamespace] someMethod:array_(arg1, arg2)]
38 53 * addCallbacks:callbackP(_fromJSONResponse) :callbackP(_fromJSONResponseError)];
  54 + * </pre>
39 55 */
40 56 @interface DKJSONServiceProxy : NSObject
41 57 {
@@ -43,8 +59,22 @@
43 59 NSString *serviceName;
44 60 }
45 61
  62 +/**
  63 + * Returns an initialized DKJSONServiceProxy which will direct method calls to
  64 + * <code>url</code>
  65 + */
46 66 - (id)initWithURL:(NSString *)url;
  67 +
  68 +/**
  69 + * Returns an initialized DKJSONServiceProxy which will direct method calls to
  70 + * <code>url</code> with the method preconfigred to <code>serviceName</code>.
  71 + */
47 72 - (id)initWithURL:(NSString *)aUrl serviceName:(NSString *)aService;
48   -- (id):(NSArray *)args; // returns deferred
  73 +
  74 +/**
  75 + * Executes a JSON-RPC call on the server. Returns a deferred which will callback
  76 + * with the native representation of the method results.
  77 + */
  78 +- (id):(NSArray *)args;
49 79
50 80 @end
2  CocoaDeferred/Source/DeferredKit/DKDeferred.h
@@ -70,7 +70,7 @@
70 70 * // tell the user the internet is down.
71 71 * return nil;
72 72 * }
73   - * </pre>
  73 + * </pre>
74 74 */
75 75
76 76 @interface DKDeferred : NSObject {
166 CocoaDeferred/Source/DeferredKit/DeferredKit.h
@@ -8,4 +8,168 @@
8 8 #import "DKDeferred.h"
9 9 #import "DKDeferred+UIKit.h"
10 10 #import "DKDeferred+JSON.h"
11   -//#import "DKDeferred+CoreLocation.h"
  11 +
  12 +/*! \mainpage DKDeferred - Deferred objects for Objective-C
  13 + <p>DeferredKit is an asynchronous library for cocoa built around the idea of a <a href="http://twistedmatrix.com/projects/core/documentation/howto/defer.html">Deferred Object</a> - that is, "an object created to encapsulate a sequence of callbacks in response to an object that may not yet be available." Besides the core class, DKDeferred, much other functionality is included in this project, including an asynchronous URL loading API, an asynchronous disk cache, and a JSON-RPC implementation.</p>
  14 +
  15 + <p>DeferredKit is modeled after the deferred class by <a href="http://twistedmatrix.com/">TwistedMatrix</a> and inspired by <a href="http://www.mochikit.com/doc/html/MochiKit/Async.html#fn-deferred">MochiKit's</a> implementation of Deferred. DKCallback - the function object is mostly taken from a pre-blocks version of <a href="http://github.com/mogeneration/functionalkit">FunctionalKit</a>.</p>
  16 +
  17 + <p>The DKDeferred implementation is not dependent upon threads or any other form of concurrency for it's operation (however, you may create threaded Deferred's) and operates in the same environment as the rest of your Objective-C program.</p>
  18 +
  19 + <p><strong>NOTE:</strong> DeferredKit bundles <a href="http://code.google.com/p/json-framework/">json-framework</a>, and will need to be removed from your project before adding DeferredKit using the following method. Otherwise, embedding the code works just as well.</p>
  20 +
  21 + <p>More:
  22 + 1. <a href="http://samuraiblog.com/wordpress/2009/11/06/json-rpc-in-objective-c/">JSON-RPC in Objective-C</a></p>
  23 +
  24 + <h2>Installing DeferredKit</h2>
  25 +
  26 + <ol>
  27 + <li>Copy the entire source tree into your projects directory.</li>
  28 + <li>Add DeferredKit to your project.
  29 +
  30 + <ul>
  31 + <li>Copy <code>"{PROJECT_ROOT}/DeferredKit/CocoaDeferred/CocoaDeferred.xcodeproj"</code></li>
  32 + <li>In the window presented by Xcode, uncheck "Copy items...". Reference type should be "Relative to Project"</li>
  33 + <li>Uncheck any targets Xcode might automatically assume.</li>
  34 + </ul>
  35 + </li>
  36 + <li>Add DeferredKit to your header search paths.
  37 +
  38 + <ul>
  39 + <li>Under your target's build settings, search for find "Header Search Paths" and add <code>"DeferredKit/CocoaDeferred/Source"</code></li>
  40 + </ul>
  41 + </li>
  42 + <li>Add DeferredKit to your Target
  43 +
  44 + <ul>
  45 + <li>Under your target's general settings, under Direct Dependancies click the "+" button and choose "DeferredKit"</li>
  46 + </ul>
  47 + </li>
  48 + <li>Expand your <code>"CocoaDeferred.xcodeproj"</code> and drag <code>"libDeferredKit.a"</code> to your target's "Link Binary with Library"</li>
  49 + </ol>
  50 +
  51 +
  52 + <h2>Example Usage</h2>
  53 +
  54 + <h3>Asynchronous URL Loading</h3>
  55 +
  56 + <p>All methods in DeferredKit return Deferred objects. This is the same basic interface used to access all functionality provided by DeferredKit.</p>
  57 +
  58 + <pre><code>\code id cbGotResource(id results) {
  59 + [[Resource resourceWithData:results] save];
  60 + return nil;
  61 + }
  62 +
  63 + id cbGetResourceFailed(id error) {
  64 + // alert user resource is unavailable.
  65 + return nil;
  66 + }
  67 +
  68 + DKDeferred *d = [DKDeferred loadURL:@"http://addr.net/resource/"];
  69 + [d addCallback:callbackP(cbGotResource)];
  70 + [d addCallback:callbackP(cbGetResourceFailed)];
  71 + \endcode</code></pre>
  72 +
  73 + <h3>Asynchronous processing</h3>
  74 +
  75 + <p>You can generate Deferred objects which encapsulate the execution of a method or function in a thread. The Deferred automatically returns the result to the correct thread.</p>
  76 +
  77 + <pre><code>\code id cbDoneProcessing(id results) {
  78 + if (content) {
  79 + [content release];
  80 + content = nil;
  81 + }
  82 + content = [results retain];
  83 + [tableView reloadData];
  84 + return nil;
  85 + }
  86 +
  87 + DKDefered *d =[DKDeferred deferInThread:
  88 + callbackTS((id)[Resource class], updateAllResources:)];
  89 + [d addCallback:cbDoneProcessing];
  90 + \endcode</code></pre>
  91 +
  92 + <h3>Combining Asynchronous tasks</h3>
  93 +
  94 + <p>These two Deferred objects may return almost immediately if loaded from the cache.</p>
  95 +
  96 + <pre><code>\code- (IBAction)loadResource:(id)sender {
  97 + DKDeferred *html = [DKDeferred loadURL:@"http://url1.com/resource" cached:YES];
  98 + DKDeferred *header = [DKDeferred loadImage:@"http://url1.com/resource-img.png" cached:YES];
  99 +
  100 + DKDeferred *d = [DKDeferred gatherResults:array_(html, header)];
  101 + [d addCalback:callbackTS(self, cbDoneLoading:)];
  102 + }
  103 +
  104 + - (id)cbDoneLoading:(id)results {
  105 + [self showHTML:[results objectAtIndex:0]];
  106 + [self showHeaderImage:[results objectAtIndex:1]];
  107 + return nil;
  108 + }
  109 + \endcode</code></pre>
  110 +
  111 + <h3>Interacting with a JSON-RPC Service</h3>
  112 +
  113 + <p>DeferredKit provides a JSON-RPC implementation using DKDeferred.</p>
  114 +
  115 + <pre><code>\code id myservice = [DKDeferred jsonService:@"" name:@"myservice"]
  116 + DKDeferred *d = [myservice someMethod:array(arg1, arg2)]
  117 + [d addCallbacks:callbackTS(self, cbGotResults:) :callbackTS(cbGetResultsFailed:)];
  118 + \endcode</code></pre>
  119 +
  120 + <h3>Asynchronous processing chain</h3>
  121 +
  122 + <p>Each callback added to a DKDeferred results in a chain of callbacks - the last callback added will be called with the result returned by the previous callback.</p>
  123 +
  124 + <pre><code>\code- (IBAction)fetchResources:(id)sender {
  125 + id _parseResults:(id results) {
  126 + // _parseResults can return an NSError at which point the deferred
  127 + // will begin it's error callback chain
  128 + return [Resource arrayWithJSONResponse:results];
  129 + }
  130 +
  131 + DKDeferred *d = [DKDeferred loadJSONDoc:@"http://whereitsat.net/resource/"]
  132 + [d addCallback:callbackP(_parseResults)];
  133 + [d addCallback:callbackTS(self, _presentResources:)];
  134 + [d addErrback:callbackTS(self, _getResourcesFailed:)];
  135 + }
  136 +
  137 + - (id)_presentResources:(id)results {
  138 + if (resources) {
  139 + [resources release];
  140 + resources = nil;
  141 + }
  142 + resources = [results retain];
  143 + [tableView reloadData];
  144 + }
  145 + \endcode</code></pre>
  146 +
  147 + <h3>Asynchronous disk cache</h3>
  148 +
  149 + <p>Since the disk cache utilizes a deferred object interface, access to cached results can implement caching in only a few lines.</p>
  150 +
  151 + <pre><code>\code- (IBAction)fetchSomeStuff:(id)sender {
  152 + id _gotKey(id results) {
  153 + if (results == [NSNull null]) { // cache miss
  154 + return [DKDeferred deferInThread:[Resource getResources] withObject:nil];
  155 + } else { // cache hit
  156 + return results;
  157 + }
  158 + }
  159 + DKDeferred *d = [[DKDeferredCache sharedCache] valueForKey:@"someKey"];
  160 + [d addCallback:callbackP(_gotKey)];
  161 + [d addCallback:callbackTS(self, cbGotResults:)];
  162 + }
  163 +
  164 + - (id)cbGotResults:(id)results {
  165 + if (isDeferred(results)) // in the event of a cache miss
  166 + return [results addCallback:callbackTS(self, cbGotResults:)];
  167 + if (resources) {
  168 + [resources release];
  169 + resources = nil;
  170 + }
  171 + resources = [results retain];
  172 + [tableView reloadData];
  173 + }
  174 + \endcode</code></pre>
  175 +*/

0 comments on commit b1358df

Please sign in to comment.
Something went wrong with that request. Please try again.