Add a method to CDVCommandDelegate for executing JS.

The method polls for pending exec() calls at the same time, so should be
used when the evall'ed JS calls callbacks of any kind.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/commit/4e52b1e6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/tree/4e52b1e6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/diff/4e52b1e6

Branch: refs/heads/master
Commit: 4e52b1e6fc8f304bde1b21ccff5811a36a31bd5a
Parents: ba7d771
Author: Andrew Grieve <agri...@chromium.org>
Authored: Wed Oct 3 16:22:20 2012 -0400
Committer: Andrew Grieve <agri...@chromium.org>
Committed: Thu Oct 4 15:00:52 2012 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVCommandDelegate.h |    5 ++-
 CordovaLib/Classes/CDVCommandQueue.h    |    3 +-
 CordovaLib/Classes/CDVCommandQueue.m    |   27 ++++++-----------
 CordovaLib/Classes/CDVPlugin.m          |    6 ++-
 CordovaLib/Classes/CDVURLProtocol.m     |    2 +-
 CordovaLib/Classes/CDVViewController.m  |   41 ++++++++++++++++++++------
 6 files changed, 52 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVCommandDelegate.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandDelegate.h 
b/CordovaLib/Classes/CDVCommandDelegate.h
index 7acf3e4..7f42785 100644
--- a/CordovaLib/Classes/CDVCommandDelegate.h
+++ b/CordovaLib/Classes/CDVCommandDelegate.h
@@ -32,8 +32,9 @@
 // being made. Instead, they should use getCommandInstance and call methods
 // directly.
 - (BOOL)execute:(CDVInvokedUrlCommand*)command;
-// Sends a plugin result to the JS. The success/failure is inferred from the
-// plugin's status.
+// Sends a plugin result to the JS.
 - (void)sendPluginResult:(CDVPluginResult*)result 
callbackId:(NSString*)callbackId;
+// Evaluates the given JS.
+- (void)evalJs:(NSString*)js;
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVCommandQueue.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandQueue.h 
b/CordovaLib/Classes/CDVCommandQueue.h
index cc522fe..9195259 100644
--- a/CordovaLib/Classes/CDVCommandQueue.h
+++ b/CordovaLib/Classes/CDVCommandQueue.h
@@ -30,12 +30,13 @@
     BOOL _currentlyExecuting;
 }
 
+@property (nonatomic, readonly) BOOL currentlyExecuting;
+
 - (id)initWithViewController:(CDVViewController*)viewController;
 - (void)resetRequestId;
 - (void)enqueCommandBatch:(NSString*)batchJSON;
 
 - (void)maybeFetchCommandsFromJs:(NSNumber*)requestId;
-- (void)executeCommandsFromJson:(NSString*)queuedCommandsJSON;
 - (void)fetchCommandsFromJs;
 - (void)executePending;
 - (BOOL)execute:(CDVInvokedUrlCommand*)command;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVCommandQueue.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCommandQueue.m 
b/CordovaLib/Classes/CDVCommandQueue.m
index f547663..a7d2126 100644
--- a/CordovaLib/Classes/CDVCommandQueue.m
+++ b/CordovaLib/Classes/CDVCommandQueue.m
@@ -17,12 +17,15 @@
  under the License.
  */
 
+#include <objc/message.h>
 #import "CDV.h"
 #import "CDVCommandQueue.h"
 #import "CDVViewController.h"
 
 @implementation CDVCommandQueue
 
+@synthesize currentlyExecuting = _currentlyExecuting;
+
 - (id)initWithViewController:(CDVViewController*)viewController
 {
     self = [super init];
@@ -40,20 +43,10 @@
 
 - (void)enqueCommandBatch:(NSString*)batchJSON
 {
-    [_queue addObject:batchJSON];
-}
-
-/**
- * Fetches the command queue and executes each command. It is possible that the
- * queue will not be empty after this function has completed since the executed
- * commands may have run callbacks which queued more commands.
- *
- * Returns the number of executed commands.
- */
-- (void)executeCommandsFromJson:(NSString*)queuedCommandsJSON
-{
-    [self enqueCommandBatch:queuedCommandsJSON];
-    [self executePending];
+    if ([batchJSON length] > 0) {
+        [_queue addObject:batchJSON];
+        [self executePending];
+    }
 }
 
 - (void)maybeFetchCommandsFromJs:(NSNumber*)requestId
@@ -81,12 +74,12 @@
     for (;; ) {
         // Grab all the queued commands from the JS side.
         NSString* queuedCommandsJSON = [_viewController.webView 
stringByEvaluatingJavaScriptFromString:
-            @"cordova.require('cordova/plugin/ios/nativecomm')()"];
+            @"cordova.require('cordova/exec').nativeFetchMessages()"];
 
-        if ([@"[]" isEqualToString:queuedCommandsJSON]) {
+        if ([queuedCommandsJSON length] == 0) {
             break;
         }
-        [self executeCommandsFromJson:queuedCommandsJSON];
+        [self enqueCommandBatch:queuedCommandsJSON];
     }
 
     [_viewController.webView stringByEvaluatingJavaScriptFromString:

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVPlugin.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVPlugin.m b/CordovaLib/Classes/CDVPlugin.m
index a747d75..5039396 100644
--- a/CordovaLib/Classes/CDVPlugin.m
+++ b/CordovaLib/Classes/CDVPlugin.m
@@ -127,12 +127,14 @@
 
 - (NSString*)success:(CDVPluginResult*)pluginResult 
callbackId:(NSString*)callbackId
 {
-    return [self writeJavascript:[pluginResult 
toSuccessCallbackString:callbackId]];
+    [self.commandDelegate evalJs:[pluginResult 
toSuccessCallbackString:callbackId]];
+    return @"";
 }
 
 - (NSString*)error:(CDVPluginResult*)pluginResult 
callbackId:(NSString*)callbackId
 {
-    return [self writeJavascript:[pluginResult 
toErrorCallbackString:callbackId]];
+    [self.commandDelegate evalJs:[pluginResult 
toErrorCallbackString:callbackId]];
+    return @"";
 }
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVURLProtocol.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVURLProtocol.m 
b/CordovaLib/Classes/CDVURLProtocol.m
index 3d59f1f..012775d 100644
--- a/CordovaLib/Classes/CDVURLProtocol.m
+++ b/CordovaLib/Classes/CDVURLProtocol.m
@@ -96,7 +96,7 @@ static NSMutableSet* gRegisteredControllers = nil;
         }
         BOOL hasCmds = [queuedCommandsJSON length] > 0;
         if (hasCmds) {
-            SEL sel = @selector(executeCommandsFromJson:);
+            SEL sel = @selector(enqueCommandBatch:);
             [viewController.commandQueue performSelectorOnMainThread:sel 
withObject:queuedCommandsJSON waitUntilDone:NO];
         } else {
             SEL sel = @selector(maybeFetchCommandsFromJs:);

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/4e52b1e6/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m 
b/CordovaLib/Classes/CDVViewController.m
index c6251c2..a3632f5 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -663,7 +663,7 @@
 + (NSString*)applicationDocumentsDirectory
 {
     NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
NSUserDomainMask, YES);
-    NSString* basePath = ([paths count] > 0) ?[paths objectAtIndex:0] : nil;
+    NSString* basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
 
     return basePath;
 }
@@ -794,23 +794,46 @@ BOOL gSplashScreenShown = NO;
 }
 
 #pragma mark CordovaCommands
+- (void)evalJsHelper:(NSString*)js
+{
+    void (^doIt)() = ^{
+        NSString* commandsJSON = [self.webView 
stringByEvaluatingJavaScriptFromString:js];
+        [_commandQueue enqueCommandBatch:commandsJSON];
+    };
+
+    // Cycle the run-loop before executing the JS.
+    // This works around a bug where sometimes alerts() within callbacks can 
cause
+    // dead-lock.
+    // If the commandQueue is currently executing, then we know that it is 
safe to
+    // execute the callback immediately.
+    if (![NSThread isMainThread] || !_commandQueue.currentlyExecuting) {
+        dispatch_async (dispatch_get_main_queue (), doIt);
+    } else {
+        doIt ();
+    }
+}
 
 - (void)sendPluginResult:(CDVPluginResult*)result 
callbackId:(NSString*)callbackId
 {
     int status = [result.status intValue];
     BOOL keepCallback = [result.keepCallback boolValue];
-    id message = result.message == nil ?[NSNull null] : result.message;
+    id message = result.message == nil ? [NSNull null] : result.message;
 
     // Use an array to encode the message as JSON.
     message = [NSArray arrayWithObject:message];
     NSString* encodedMessage = [message cdvjk_JSONString];
     // And then strip off the outer []s.
-    encodedMessage = [encodedMessage substringWithRange:NSMakeRange(1, 
[encodedMessage length] - 2)];
+    encodedMessage = [encodedMessage substringWithRange:NSMakeRange (1, 
[encodedMessage length] - 2)];
     NSString* js = [NSString 
stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)",
         callbackId, status, encodedMessage, keepCallback];
 
-    NSString* commandsJSON = [self.webView 
stringByEvaluatingJavaScriptFromString:js];
-    [_commandQueue enqueCommandBatch:commandsJSON];
+    [self evalJsHelper:js];
+}
+
+- (void)evalJs:(NSString*)js
+{
+    js = [js 
stringByAppendingString:@";cordova.require('cordova/exec').nativeFetchMessages()"];
+    [self evalJsHelper:js];
 }
 
 - (BOOL)execute:(CDVInvokedUrlCommand*)command
@@ -861,7 +884,7 @@ BOOL gSplashScreenShown = NO;
         if ((obj != nil) && [obj isKindOfClass:[CDVPlugin class]]) {
             [self registerPlugin:obj withClassName:className];
         } else {
-            NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", 
className, pluginName);
+            NSLog (@"CDVPlugin class %@ (pluginName: %@) does not exist.", 
className, pluginName);
         }
     }
     return obj;
@@ -898,9 +921,9 @@ BOOL gSplashScreenShown = NO;
     NSString* plistPath = [[NSBundle mainBundle] pathForResource:plistName 
ofType:@"plist"];
     NSData* plistXML = [[NSFileManager defaultManager] 
contentsAtPath:plistPath];
     NSDictionary* temp = (NSDictionary*)[NSPropertyListSerialization
-        propertyListFromData:plistXML
-            mutabilityOption:NSPropertyListMutableContainersAndLeaves
-                      format:&format errorDescription:&errorDesc];
+propertyListFromData: plistXML
+mutabilityOption: NSPropertyListMutableContainersAndLeaves
+format: &format errorDescription : &errorDesc];
 
     return temp;
 }

Reply via email to