You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2012/04/21 03:12:06 UTC

ios commit: Fixed CB-391 - camera.getPicture crash

Updated Branches:
  refs/heads/master 3794f4db6 -> 499cf514f


Fixed CB-391 - camera.getPicture crash


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/499cf514
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/tree/499cf514
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/diff/499cf514

Branch: refs/heads/master
Commit: 499cf514fd29cd33f22baa796ace8eb8e725b8b6
Parents: 3794f4d
Author: Shazron Abdullah <sh...@apache.org>
Authored: Fri Apr 20 18:11:59 2012 -0700
Committer: Shazron Abdullah <sh...@apache.org>
Committed: Fri Apr 20 18:11:59 2012 -0700

----------------------------------------------------------------------
 CordovaLib/Classes/CDVCamera.h         |    5 +-
 CordovaLib/Classes/CDVCamera.m         |  398 +++++++++++++++------------
 CordovaLib/Classes/CDVPlugin.h         |    2 +
 CordovaLib/Classes/CDVPlugin.m         |    8 +-
 CordovaLib/Classes/CDVViewController.m |   28 ++-
 5 files changed, 256 insertions(+), 185 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/499cf514/CordovaLib/Classes/CDVCamera.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCamera.h b/CordovaLib/Classes/CDVCamera.h
index 6d7661d..9a066ab 100644
--- a/CordovaLib/Classes/CDVCamera.h
+++ b/CordovaLib/Classes/CDVCamera.h
@@ -54,6 +54,8 @@ typedef NSUInteger CDVMediaType;
 @property (assign) bool correctOrientation;
 @property (assign) bool saveToPhotoAlbum;
 @property (assign) bool cropToSize;
+@property (retain) UIWebView* webView;
+@property (assign) BOOL popoverSupported;
 
 - (void) dealloc;
 
@@ -65,7 +67,6 @@ typedef NSUInteger CDVMediaType;
 									UINavigationControllerDelegate,
 									UIPopoverControllerDelegate>
 {
-	CDVCameraPicker* pickerController;
 }
 
 @property (retain) CDVCameraPicker* pickerController;
@@ -89,6 +90,8 @@ typedef NSUInteger CDVMediaType;
 - (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize;
 - (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize;
 - (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage;
+
+- (void) closePicker:(CDVCameraPicker*)picker;
 - (void) dealloc;
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/499cf514/CordovaLib/Classes/CDVCamera.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCamera.m b/CordovaLib/Classes/CDVCamera.m
index 3102193..5dc077d 100644
--- a/CordovaLib/Classes/CDVCamera.m
+++ b/CordovaLib/Classes/CDVCamera.m
@@ -22,15 +22,23 @@
 #import "NSDictionary+Extensions.h"
 #import <MobileCoreServices/UTCoreTypes.h>
 
+
+@interface CDVCamera ()
+
+@property (readwrite, assign) BOOL hasPendingOperation;
+
+@end
+
 @implementation CDVCamera
 
-@synthesize pickerController;
+@synthesize hasPendingOperation, pickerController;
 
--(BOOL)popoverSupported
+- (BOOL) popoverSupported
 {
 	return ( NSClassFromString(@"UIPopoverController") != nil) && 
 	(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
 }
+
 /*  takePicture arguments:
  * INDEX   ARGUMENT
  *  0       callbackId
@@ -48,7 +56,8 @@
 - (void) takePicture:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
 {
 	NSString* callbackId = [arguments objectAtIndex:0];
-	
+    self.hasPendingOperation = NO;
+
 	NSString* sourceTypeString = [arguments objectAtIndex:3];
 	UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; // default
 	if (sourceTypeString != nil) 
@@ -61,218 +70,247 @@
 		NSLog(@"Camera.getPicture: source type %d not available.", sourceType);
 		CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: @"no camera available"];
         [self writeJavascript:[result toErrorCallbackString:callbackId]];
+        return;
         
-	} else {
-        bool allowEdit = [[arguments objectAtIndex:8] boolValue];
-        NSNumber* targetWidth = [arguments objectAtIndex:4];
-        NSNumber* targetHeight = [arguments objectAtIndex:5];
-        NSNumber* mediaValue = [arguments objectAtIndex:7];
-        CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture;
-        
-        CGSize targetSize = CGSizeMake(0, 0);
-        if (targetWidth != nil && targetHeight != nil) {
-            targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
-        }
-        
-        
-        if (self.pickerController == nil) 
-        {
-            self.pickerController = [[[CDVCameraPicker alloc] init] autorelease];
-        }
-        
-        self.pickerController.delegate = self;
-        self.pickerController.sourceType = sourceType;
-        self.pickerController.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
-        self.pickerController.callbackId = callbackId;
-        self.pickerController.targetSize = targetSize;
-        self.pickerController.cropToSize = NO;
-        
-        self.pickerController.correctOrientation = [[arguments objectAtIndex:9] boolValue];
-        self.pickerController.saveToPhotoAlbum = [[arguments objectAtIndex:10] boolValue];
-        
-        self.pickerController.encodingType = ([arguments objectAtIndex:6]) ? [[arguments objectAtIndex:6] intValue] : EncodingTypeJPEG;
+	} 
+
+    bool allowEdit = [[arguments objectAtIndex:8] boolValue];
+    NSNumber* targetWidth = [arguments objectAtIndex:4];
+    NSNumber* targetHeight = [arguments objectAtIndex:5];
+    NSNumber* mediaValue = [arguments objectAtIndex:7];
+    CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture;
+    
+    CGSize targetSize = CGSizeMake(0, 0);
+    if (targetWidth != nil && targetHeight != nil) {
+        targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
+    }
+    
+    CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
+    self.pickerController = cameraPicker;
+    
+    cameraPicker.delegate = self;
+    cameraPicker.sourceType = sourceType;
+    cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
+    cameraPicker.callbackId = callbackId;
+    cameraPicker.targetSize = targetSize;
+    cameraPicker.cropToSize = NO;
+    // we need to capture this state for memory warnings that dealloc this object
+    cameraPicker.webView = self.webView;
+    cameraPicker.popoverSupported = [self popoverSupported];
+    
+    cameraPicker.correctOrientation = [[arguments objectAtIndex:9] boolValue];
+    cameraPicker.saveToPhotoAlbum = [[arguments objectAtIndex:10] boolValue];
+    
+    cameraPicker.encodingType = ([arguments objectAtIndex:6]) ? [[arguments objectAtIndex:6] intValue] : EncodingTypeJPEG;
+    
+    cameraPicker.quality = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : 50;
+    cameraPicker.returnType = ([arguments objectAtIndex:2]) ? [[arguments objectAtIndex:2] intValue] : DestinationTypeFileUri;
+   
+    if (sourceType == UIImagePickerControllerSourceTypeCamera) {
+        // we only allow taking pictures (no video) in this api
+        cameraPicker.mediaTypes = [NSArray arrayWithObjects: (NSString*) kUTTypeImage, nil];
+    } else if (mediaType == MediaTypeAll) {
+        cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType: sourceType];
+    } else {
+        NSArray* mediaArray = [NSArray arrayWithObjects: (NSString*) (mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil];
+        cameraPicker.mediaTypes = mediaArray;
+    }
+    
+    if ([self popoverSupported] && sourceType != UIImagePickerControllerSourceTypeCamera)
+    {
+        if (cameraPicker.popoverController == nil) 
+        { 
+            cameraPicker.popoverController = [[[NSClassFromString(@"UIPopoverController") alloc] 
+                                                       initWithContentViewController:cameraPicker] autorelease]; 
+        } 
+        cameraPicker.popoverController.delegate = self;
+        [cameraPicker.popoverController presentPopoverFromRect:CGRectMake(0,32,320,480)
+                                                                  inView:[self.webView superview]
+                                                permittedArrowDirections:UIPopoverArrowDirectionAny 
+                                                                animated:YES]; 
+    }
+    else 
+    { 
+        self.hasPendingOperation = YES;
         
-        self.pickerController.quality = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : 50;
-        self.pickerController.returnType = ([arguments objectAtIndex:2]) ? [[arguments objectAtIndex:2] intValue] : DestinationTypeFileUri;
-       
-        if (sourceType == UIImagePickerControllerSourceTypeCamera) {
-            // we only allow taking pictures (no video) in this api
-            self.pickerController.mediaTypes = [NSArray arrayWithObjects: (NSString*) kUTTypeImage, nil];
-        } else if (mediaType == MediaTypeAll) {
-            self.pickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType: sourceType];
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:cameraPicker animated:YES completion:nil];        
         } else {
-            NSArray* mediaArray = [NSArray arrayWithObjects: (NSString*) (mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil];
-            self.pickerController.mediaTypes = mediaArray;
-            
-        }
-        
-        if([self popoverSupported] && sourceType != UIImagePickerControllerSourceTypeCamera)
-        {
-            if (self.pickerController.popoverController == nil) 
-            { 
-                self.pickerController.popoverController = [[[NSClassFromString(@"UIPopoverController") alloc] 
-                                                           initWithContentViewController:self.pickerController] autorelease]; 
-            } 
-            self.pickerController.popoverController.delegate = self;
-            [ self.pickerController.popoverController presentPopoverFromRect:CGRectMake(0,32,320,480)
-                                                                      inView:[self.webView superview]
-                                                    permittedArrowDirections:UIPopoverArrowDirectionAny 
-                                                                    animated:YES]; 
-        }
-        else 
-        { 
-            if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
-                [self.viewController presentViewController:self.pickerController animated:YES completion:nil];        
-            } else {
-                [self.viewController presentModalViewController:self.pickerController animated:YES ];
-            }              
-        }
+            [self.viewController presentModalViewController:cameraPicker animated:YES ];
+        }              
     }
+    
+    [cameraPicker release];
 }
 
 
-- (void)popoverControllerDidDismissPopover:(id)popoverController
+- (void) popoverControllerDidDismissPopover:(id)popoverController
 {
-    [ self imagePickerControllerDidCancel:self.pickerController ];	
+    //[ self imagePickerControllerDidCancel:self.pickerController ];	'
+    UIPopoverController* pc = (UIPopoverController*)popoverController;
+    [pc dismissPopoverAnimated:YES]; 
+    pc.delegate = nil;
 }
 
 - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
 {
+    CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
 
-	NSString* callbackId =  self.pickerController.callbackId;
+	NSString* callbackId =  cameraPicker.callbackId;
 	
-	if([self popoverSupported] && self.pickerController.popoverController != nil)
+	if(cameraPicker.popoverSupported && cameraPicker.popoverController != nil)
 	{
-		[self.pickerController.popoverController dismissPopoverAnimated:YES]; 
-		self.pickerController.popoverController.delegate = nil;
-		self.pickerController.popoverController = nil;
+		[cameraPicker.popoverController dismissPopoverAnimated:YES]; 
+		cameraPicker.popoverController.delegate = nil;
+		cameraPicker.popoverController = nil;
 	}
 	else 
 	{
-        if ([self.pickerController respondsToSelector:@selector(presentingViewController)]) { 
-            [[self.pickerController presentingViewController] dismissModalViewControllerAnimated:YES];
+        if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { 
+            [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
         } else {
-            [[self.pickerController parentViewController] dismissModalViewControllerAnimated:YES];
+            [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
         }        
 	}
+     
 	NSString* jsString = nil;
     CDVPluginResult* result = nil;
     
 	NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
+    // IMAGE TYPE
 	if ([mediaType isEqualToString:(NSString*)kUTTypeImage])
 	{
-		
-		
-		
 		// get the image
 		UIImage* image = nil;
-		if (self.pickerController.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]){
+		if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]){
 			image = [info objectForKey:UIImagePickerControllerEditedImage];
-		}else {
+		} else {
 			image = [info objectForKey:UIImagePickerControllerOriginalImage];
 		}
-    if (self.pickerController.saveToPhotoAlbum) {
-      UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
-    }
-    
-    if (self.pickerController.correctOrientation) {
-      image = [self imageCorrectedForCaptureOrientation:image];
-    }
-    
-    UIImage *scaledImage = nil;
+        
+        if (cameraPicker.saveToPhotoAlbum) {
+          UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
+        }
+        
+        if (cameraPicker.correctOrientation) {
+          image = [self imageCorrectedForCaptureOrientation:image];
+        }
     
-    if (self.pickerController.targetSize.width > 0 && self.pickerController.targetSize.height > 0) {
-        // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
-        if(self.pickerController.cropToSize) {
-            scaledImage = [self imageByScalingAndCroppingForSize:image toSize:self.pickerController.targetSize];
-        } else {
-            scaledImage = [self imageByScalingNotCroppingForSize:image toSize:self.pickerController.targetSize];
+        UIImage *scaledImage = nil;
+        
+        if (cameraPicker.targetSize.width > 0 && cameraPicker.targetSize.height > 0) {
+            // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
+            if(cameraPicker.cropToSize) {
+                scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
+            } else {
+                scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
+            }
         }
-    }
-    NSData* data = nil;
-		if (self.pickerController.encodingType == EncodingTypePNG) {
+            
+        NSData* data = nil;
+
+        if (cameraPicker.encodingType == EncodingTypePNG) {
             data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
         }
         else {
-            data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, self.pickerController.quality / 100.0f);
-		}
-        if (self.pickerController.returnType == DestinationTypeFileUri){
-			
-			// write to temp directory and reutrn URI
-			// get the temp directory path
-			NSString* docsPath = [NSTemporaryDirectory() stringByStandardizingPath];
-			NSError* err = nil;
-			NSFileManager* fileMgr = [[NSFileManager alloc] init]; //recommended by apple (vs [NSFileManager defaultManager]) to be theadsafe
-			
-			// generate unique file name
-			NSString* filePath;
-			int i=1;
-			do {
-				filePath = [NSString stringWithFormat:@"%@/photo_%03d.%@", docsPath, i++, self.pickerController.encodingType == EncodingTypePNG ? @"png" : @"jpg"];
-			} while([fileMgr fileExistsAtPath: filePath]);
-			// save file
-			if (![data writeToFile: filePath options: NSAtomicWrite error: &err]){
-				result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [err localizedDescription]];
-				jsString = [result toErrorCallbackString:callbackId];
-			}else{
-				result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [[NSURL fileURLWithPath: filePath] absoluteString]];
-				jsString = [result toSuccessCallbackString:callbackId];
-			}
-			[fileMgr release];
-			
-		}else{
-			result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [data base64EncodedString]];
-			jsString = [result toSuccessCallbackString:callbackId];
-		}
-		
-		
-	} else {
-        // was movie type
+            data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+        }
+            
+        if (cameraPicker.returnType == DestinationTypeFileUri) {
+        
+            // write to temp directory and reutrn URI
+            // get the temp directory path
+            NSString* docsPath = [NSTemporaryDirectory() stringByStandardizingPath];
+            NSError* err = nil;
+            NSFileManager* fileMgr = [[NSFileManager alloc] init]; //recommended by apple (vs [NSFileManager defaultManager]) to be theadsafe
+            
+            // generate unique file name
+            NSString* filePath;
+            
+            int i = 1;
+            do 
+            {
+                filePath = [NSString stringWithFormat:@"%@/photo_%03d.%@", docsPath, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png" : @"jpg"];
+            } 
+            while ([fileMgr fileExistsAtPath: filePath]);
+            
+            // save file
+            if (![data writeToFile: filePath options: NSAtomicWrite error: &err]) {
+                result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [err localizedDescription]];
+                jsString = [result toErrorCallbackString:callbackId];
+            } else {
+                result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [[NSURL fileURLWithPath: filePath] absoluteString]];
+                jsString = [result toSuccessCallbackString:callbackId];
+            }
+            [fileMgr release];
+        
+        } else {
+            result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [data base64EncodedString]];
+            jsString = [result toSuccessCallbackString:callbackId];
+        }
+	} 
+    // NOT IMAGE TYPE (MOVIE)
+    else 
+    {
          NSString *moviePath = [[info objectForKey: UIImagePickerControllerMediaURL] absoluteString];
         result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: moviePath];
         jsString = [result toSuccessCallbackString:callbackId];
-        
     }
+
+    
     if (jsString) {
         [self.webView stringByEvaluatingJavaScriptFromString:jsString];
     }
-	
-	self.pickerController.delegate = nil;
-	self.pickerController = nil;
+
+        self.hasPendingOperation = NO;
 }
 
 // older api calls newer didFinishPickingMediaWithInfo
-- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo
+- (void) imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo
 {
 	NSDictionary* imageInfo = [NSDictionary dictionaryWithObject:image forKey:UIImagePickerControllerOriginalImage];
 	[self imagePickerController:picker didFinishPickingMediaWithInfo: imageInfo];
 }
 
-- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
-{	
-	NSString* callbackId = self.pickerController.callbackId;
-	
-    if ([picker respondsToSelector:@selector(presentingViewController)]) { 
-        [[picker presentingViewController] dismissModalViewControllerAnimated:YES];
+- (void) closePicker:(CDVCameraPicker*)cameraPicker
+{
+    if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { 
+        [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
     } else {
-        [[picker parentViewController] dismissModalViewControllerAnimated:YES];
+        [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
     }        
-	
-	CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: @"no image selected"]; // error callback expects string ATM
+    
+    if (cameraPicker.popoverSupported && cameraPicker.popoverController != nil)
+    {
+        cameraPicker.popoverController.delegate = nil;
+        cameraPicker.popoverController = nil;
+    }
+}
 
-	[self.webView stringByEvaluatingJavaScriptFromString:[result toErrorCallbackString: callbackId]];
-	
-	if([self popoverSupported] && self.pickerController.popoverController != nil)
-	{
-		self.pickerController.popoverController.delegate = nil;
-		self.pickerController.popoverController = nil;
-	}
-	
-	self.pickerController.delegate = nil;
-	self.pickerController = nil;
-	
+- (void) imagePickerControllerDidCancel:(UIImagePickerController*)picker
+{	
+    CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+	NSString* callbackId = cameraPicker.callbackId;
+    
+    if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) { 
+        [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
+    } else {
+        [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
+    }        
+    
+    if (cameraPicker.popoverSupported && cameraPicker.popoverController != nil)
+    {
+        cameraPicker.popoverController.delegate = nil;
+        cameraPicker.popoverController = nil;
+    }
+        
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: @"no image selected"]; // error callback expects string ATM
+    [cameraPicker.webView stringByEvaluatingJavaScriptFromString:[result toErrorCallbackString: callbackId]];
+    
+    self.hasPendingOperation = NO;
 }
-- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize
+
+- (UIImage*) imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize
 {
     UIImage *sourceImage = anImage;
     UIImage *newImage = nil;        
@@ -303,11 +341,10 @@
         {
             thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
         }
-        else 
-            if (widthFactor < heightFactor)
-            {
-                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
-            }
+        else if (widthFactor < heightFactor)
+        {
+            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
+        }
     }       
     
     UIGraphicsBeginImageContext(targetSize); // this will crop
@@ -320,18 +357,20 @@
     [sourceImage drawInRect:thumbnailRect];
     
     newImage = UIGraphicsGetImageFromCurrentImageContext();
-    if(newImage == nil) 
+    if(newImage == nil) {
         NSLog(@"could not scale image");
+    }
     
     //pop the context to get back to the default
     UIGraphicsEndImageContext();
     return newImage;
 }
 
-- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage
+- (UIImage*) imageCorrectedForCaptureOrientation:(UIImage*)anImage
 {   
    float rotation_radians = 0;
    bool perpendicular = false;
+
    switch ([anImage imageOrientation]) {
     case UIImageOrientationUp:
       rotation_radians = 0.0;
@@ -373,7 +412,7 @@
    return newImage;
 }
 
-- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize
+- (UIImage*) imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize
 {
     UIImage *sourceImage = anImage;
     UIImage *newImage = nil;        
@@ -391,10 +430,11 @@
         CGFloat heightFactor = targetHeight / height;
         
         // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds
-        if (widthFactor > heightFactor) 
+        if (widthFactor > heightFactor) {
             scaleFactor = heightFactor; // scale to fit height
-        else
+        } else {
             scaleFactor = widthFactor; // scale to fit width
+        }
         scaledSize = CGSizeMake(width * scaleFactor, height * scaleFactor);
     }
     
@@ -403,8 +443,9 @@
     [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
     
     newImage = UIGraphicsGetImageFromCurrentImageContext();
-    if(newImage == nil) 
+    if(newImage == nil) {
         NSLog(@"could not scale image");
+    }
     
     //pop the context to get back to the default
     UIGraphicsEndImageContext();
@@ -413,6 +454,8 @@
 
 - (void) postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url 
 {
+    self.hasPendingOperation = YES;
+    
 	NSString *boundary = @"----BOUNDARY_IS_I";
 
 	NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
@@ -446,16 +489,13 @@
 
 //  NSData* result = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
 //	NSString * resultStr =  [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease];
+    
+    self.hasPendingOperation = NO;
 }
 
 
 - (void) dealloc
 {
-	if (self.pickerController) 
-	{
-		self.pickerController.delegate = nil;
-	}
-	self.pickerController = nil;
 	[super dealloc];
 }
 
@@ -473,15 +513,11 @@
 @synthesize saveToPhotoAlbum;
 @synthesize encodingType;
 @synthesize cropToSize;
-
+@synthesize webView;
+@synthesize popoverSupported;
 
 - (void) dealloc
 {
-	if (callbackId) {
-		[callbackId release];
-	}
-	
-	
 	[super dealloc];
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/499cf514/CordovaLib/Classes/CDVPlugin.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVPlugin.h b/CordovaLib/Classes/CDVPlugin.h
index b2b03cf..658cfbd 100644
--- a/CordovaLib/Classes/CDVPlugin.h
+++ b/CordovaLib/Classes/CDVPlugin.h
@@ -37,6 +37,8 @@ callerFileName:__FILE__ callerFunctionName:__PRETTY_FUNCTION__]) { return; }
 @property (nonatomic, retain) UIViewController* viewController;
 @property (nonatomic, retain) id<CDVCommandDelegate> commandDelegate;
 
+@property (readonly, assign) BOOL hasPendingOperation;
+
 - (CDVPlugin*) initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings;
 - (CDVPlugin*) initWithWebView:(UIWebView*)theWebView;
 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/499cf514/CordovaLib/Classes/CDVPlugin.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVPlugin.m b/CordovaLib/Classes/CDVPlugin.m
index cdb4821..2ebf4ef 100644
--- a/CordovaLib/Classes/CDVPlugin.m
+++ b/CordovaLib/Classes/CDVPlugin.m
@@ -20,9 +20,14 @@
 
 #import "CDVPlugin.h"
 
+@interface CDVPlugin ()
+
+@property (readwrite, assign) BOOL hasPendingOperation;
+
+@end
 
 @implementation CDVPlugin
-@synthesize webView, settings, viewController, commandDelegate;
+@synthesize webView, settings, viewController, commandDelegate, hasPendingOperation;
 
 
 - (CDVPlugin*) initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings
@@ -30,6 +35,7 @@
     self = [self initWithWebView:theWebView];
     if (self) {
         self.settings = classSettings;
+        self.hasPendingOperation = NO;
 	}
     return self;
 }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/499cf514/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index d9d00c9..24c8d93 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -336,8 +336,29 @@
 }
 
 - (void) didReceiveMemoryWarning {
-	// Releases the view if it doesn't have a superview.
-    [super didReceiveMemoryWarning];
+    
+    // iterate through all the plugin objects, and call hasPendingOperation
+    // if at least one has a pending operation, we don't call [super didReceiveMemoryWarning]
+    
+    NSEnumerator* enumerator = [self.pluginObjects objectEnumerator];
+    CDVPlugin* plugin;
+    
+    BOOL doPurge = YES;
+    while ((plugin = [enumerator nextObject])) 
+    {
+        if (plugin.hasPendingOperation) {
+            NSLog(@"Plugin '%@' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class]));
+            doPurge = NO;
+        }
+    }
+    
+	if (doPurge) {
+        // Releases the view if it doesn't have a superview.
+        [super didReceiveMemoryWarning];
+    } else {
+        // try again in 10 seconds
+        [self performSelector:@selector(didReceiveMemoryWarning) withObject:nil afterDelay:10];
+    }
 	
 	// Release any cached data, images, etc. that aren't in use.
 }
@@ -346,6 +367,9 @@
 - (void) viewDidUnload {
 	// Release any retained subviews of the main view.
 	// e.g. self.myOutlet = nil;
+    
+    self.webView.delegate = nil;
+    self.webView = nil;
 }