I am working on a web application that uses html5, css3, and jquery as the app. We run the web files through XCODE and use XCODE to upload the "apps" to iPads.
Recently we have been getting a memory warning and a crash after the splash screen spins for a few seconds.
The apps work fine in the XCODE simulator, and we have noticed that it seems to happen when the app has video files (even small ones like 800KB).
Here is the console from running the app on the iPad.
How do we prevent this crash?
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Multi-tasking -> Device: YES, App: YES Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 kernel[0] : launchd[4020] Builtin profile: container (sandbox)
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 kernel[0] : launchd[4020] Container: /private/var/mobile/Applications/997C5F22-C5A6-4A05-96C8-8ABEA9DAAC8A (sandbox)
Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Resetting plugins due to page load.
Aug 15 11:50:15 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Received memory warning.
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 UserEventAgent[13] : jetsam: kernel termination snapshot being created
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 com.apple.launchd1 (UIKitApplication:com.bd.Push.us.y[0x4721][4020]) : (UIKitApplication:com.bd.Push.us.y[0x4721]) Exited: Killed: 9
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 backboardd[26] : Application 'UIKitApplication:com.bd.Push.us.y[0x4721]' exited abnormally with signal 9: Killed: 9
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 ReportCrash[4021] : libMobileGestalt copySystemVersionDictionaryValue: Could not lookup ReleaseType from system version dictionary
Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 ReportCrash[4021] : Saved crashreport to /Library/Logs/CrashReporter/LowMemory-2013-08-15-115017.plist using uid: 0 gid: 0, synthetic_euid: 0 egid: 0
AppDelegate.m
@implementation AppDelegate
@synthesize window, viewController;
- (id)init
{
/** If you need to do any extra app-specific initialization, you can do it here
* -jm
**/
NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
#if __has_feature(objc_arc)
NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
#else
NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
#endif
[NSURLCache setSharedURLCache:sharedCache];
self = [super init];
return self;
}
#pragma mark UIApplicationDelegate implementation
/**
* This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
*/
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
int cacheSizeMemory = 16*1024*1024; // 16MB
int cacheSizeDisk = 32*1024*1024; // 32MB
NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
[NSURLCache setSharedURLCache:sharedCache];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
#if __has_feature(objc_arc)
self.window = [[UIWindow alloc] initWithFrame:screenBounds];
#else
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
#endif
self.window.autoresizesSubviews = YES;
#if __has_feature(objc_arc)
self.viewController = [[MainViewController alloc] init];
#else
self.viewController = [[[MainViewController alloc] init] autorelease];
#endif
self.viewController.useSplashScreen = YES;
// Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.
// If necessary, uncomment the line below to override it.
// self.viewController.startPage = @"index.html";
// NOTE: To customize the view's frame size (which defaults to full screen), override
// [self.viewController viewWillAppear:] in your view controller.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
// this happens while we are running ( in the background, or from within our own app )
// only valid if flush.ca.mbp-Info.plist specifies a protocol to handle
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
if (!url) {
return NO;
}
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:@"handleOpenURL(\"%@\");", url];
[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];
// all plugins will get the notification, and their handlers will be called
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
return YES;
}
// repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
- (void) application:(UIApplication*)application
didReceiveLocalNotification:(UILocalNotification*)notification
{
// re-post ( broadcast )
[[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification];
}
- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
// iPhone doesn't support upside down by default, while the iPad does. Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected).
NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown);
return supportedInterfaceOrientations;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
{
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSLog(@"Cache Cleared");
}
CDVViewController.m
- (void)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];
}
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.webView.delegate = nil;
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
}
#pragma mark UIWebViewDelegate
/**
When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and
the device's data such as device ID, platform version, etc.
*/
- (void)webViewDidStartLoad:(UIWebView*)theWebView
{
NSLog(@"Resetting plugins due to page load.");
[_commandQueue resetRequestId];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
}
/**
Called when the webview finishes loading. This stops the activity view.
*/
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
NSLog(@"Finished load of: %@", theWebView.request.URL);
// It's safe to release the lock even if this is just a sub-frame that's finished loading.
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
/*
* Hide the Top Activity THROBBER in the Battery Bar
*/
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self processOpenUrl];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
}