How to handle a system alert message for iOS? - iphone

I have an app where i am using UIImagePickerController to use the native camer inorder to click pictures but the when the photo gallery on the device is full. I get a alert message which says "Cannot Take Photo - There is not enough available storage to take a photo.You can manage your storage in Settings". I am given two options to click the "Done" button or "Settings" button. Clicking either of them does nothing and the app freezes completely.
This is what i get from the console logs
Not enough space to take a picture. Available space is 0
The code for the picker
UIImagePickerController *mediaPicker = [[UIImagePickerController alloc] init];
mediaPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
mediaPicker.delegate=self;
mediaPicker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:mediaPicker animated:YES];
I have implemented and tried all the delegates already and its not calling any delegate.
Is there any way i can implement something where i can use a listener to detect when this error occurs and take back the user to the previous screen ?

Sounds like your device run out of memory, system sent lots of "Out of Memory" notifications and your app got one, too. As result your app released the UIViewController, which originally launched UIImagePickerController.
Now when you dismiss imagePicker with Done/Settings button, control returns back to your app. The old UIViewController doesn't exist any more and you haven't implemented code to recreate it from scratch in this kind of situations. The device looks like it frozen, but only because UI wasn't redrawn by your app. Otherwise app works just fine.
You can check this case by implementing didReceiveMemoryWarning method into every UIViewController and logging, if it's called:
- (void)didReceiveMemoryWarning
{
NSLog(#"%#", [self description]);
[super didReceiveMemoryWarning];
}
One of my favourite bugs. Easy to miss :)

This sounds like a bug in iOS.
You should file a feedback at https://feedbackassistant.apple.com/.

Related

Keyboard shows then immediately hides itself when showing MFMessageComposeViewController

I am building a PhoneGap app using Cordova 2.2 for IOS. I am experiencing some bizarre behavior when calling out to a native obj-c plugin I have written to show the MFMessageComposeViewController.
The setup is very simple - I have a tap event attached to a UI element, that when pressed, will make a call to my PhoneGap plugin, pass with it a number and a text message, then show the MFMessageComposeViewController with the parameters pre-populated.
My javascript looks like this:
$(document).bind('deviceready', function(){
$(".theButton").tap(function(){
cordova.exec(function(){}, function() {}, "PhoneGapSms", "SendSms", [db.getItem("profile_sms"), db.getItem("profile_emergency")]);
});
});
And my obj-c code looks like this:
- (void)SendSms:(CDVInvokedUrlCommand*)command
{
CDVInvokedUrlCommand* myCommand = command;
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
NSString* body = [command.arguments objectAtIndex:0];
NSString* toRecipientsString = [command.arguments objectAtIndex:1];
if(body != nil)
picker.body = body;
if(toRecipientsString != nil)
[picker setRecipients:[ toRecipientsString componentsSeparatedByString:#","]];
picker.messageComposeDelegate = self;
[self.viewController presentModalViewController:picker animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[picker release];
}
So, all in all, very simple stuff.
My Problem is this:
When my iPhone is plugged into my Mac and the app is run from XCode, the Message Composer overlay appears great, with my values pre-populated. Image below demonstrating the SMS interface appears fine while plugged into XCode:
When my iPhone is unplugged from my Mac, and the app is run from the spring board, the Overlay slides up, the keyboard begins to slide up, then immediately slides down - making it impossible to type or send the message. This is what it looks like when not attached to the Mac/Xcode - the keyboard begins to slide up then immediately slides down (~ < 1 sec) leaving the following interface:
I can't for the life of me figure out what would cause the keyboard to hide when not running from XCode, but work perfectly well when it is.
Is there any way to 'force' the keyboard to display, or possibly put the whole modalviewcontroller as first responder in some form or fashion?
Any suggestions are appreciated!
Edit:
The keyboard WILL appear again if you click in the contact area
You must add MessageUI.framework to your Xcode project and include a
#import <MessageUI/MessageUI.h> in your header file.
try this code may be its helpful to you..
[self presentModalViewController:picker animated:YES];
//[self becomeFirstResponder];//try picker also instead of self
Also Refer this bellow tutorial and also check demo..
new-tutorial-developing-and-architecting-a-phonegap-application
SMSComposer
i hope this help you...
I encountered these symptoms with a Sencha Touch 2.2 and Cordova 2.6.0 setup (specifically, iOS 6+ devices).
The issue was with the web framework stealing focus away from the native SMS Composer modal, typically occurring after the first SMS Composer modal had been successfully displayed and closed.
A event.preventDefault() and event.stopPropagation() call once the event had been fired (or event.stopEvent() in Sencha land) resolved this.
Hope this helps,
-James
First: The most likely culprit, without seeing your code, is that your parent (presenting) view controller may have an action in its viewWillDisappear or viewDidDisappear that is affecting who has the "first" responder. These methods get called when presenting a view controller modally. It may be behaving differently on the simulator than the device due to timing - often really close timing conditions are different on the ARM device and the i386 processor.
Second: Does anywhere in your app register for the UIKeyboardWillShowNotification or the UIKeyboardDidShowNotification? If so, put breakpoints in the methods that are called as a result - it's possible some other controller in your view hierarchy is interfering with this one.
To answer your question...
Is there any way to 'force' the keyboard to display, or possibly put the whole modalviewcontroller as first responder in some form or fashion?
No to both. The only way to make the keyboard display is to call the becomeFirstResponder method of the input view. Since Apple doesn't expose the text view, you cannot send it messages. Setting the modalViewController as first responder would be setting the wrong object.
I found the same type of issue But Not Sure it will Solve your problem or not Just Have a Look on the Following Links :
1. http://community.phonegap.com/nitobi/topics/keyboard_is_not_triggerd_in_my_ios_build
2. https://github.com/phonegap/build/issues/31
If its not Solving your issue then you can Download the Sample code Here.
Link: https://github.com/phonegap/phonegap-plugins/tree/master/iPhone/SMSComposer

How to push new view controller in didReceiveRemoteNotification so that previous view controller doesnt show for a moment?

I receive a pust notification and push a view controller based on the data i get in push.
I do it like this:
UINavigationController *navVc=(UINavigationController *) self.window.rootViewController;
PictureTakeVC *pvc=[[PictureTakeVC alloc] init];
[navVc pushViewController:pvc animated:NO];
It works, but the view controller that was opened before i pressed home button shows for a moment.
I also tried this but it happens the same:
PictureTakeVC *pvc=[[PictureTakeVC alloc] init];
NSArray *vcs=[[NSArray alloc] initWithObjects: pvc, nil];
UINavigationController *navVc=(UINavigationController *) self.window.rootViewController;
navVc.viewControllers=vcs;
self.window.rootViewController = navVc;
How to push vc didReceiveRemoteNotification so that it opens immediatly and no other vc is shown for a moment?
As you said "but the view controller that was opened before i pressed home button shows for a moment.",
The reason is not the code, but the iOS system.
It captures screenshot of the screen when app goes in background. As documented:
Remove sensitive information from views before moving to the
background. When an app transitions to the background, the system
takes a snapshot of the app’s main window, which it then presents
briefly when transitioning your app back to the foreground. Before
returning from your applicationDidEnterBackground: method, you should
hide or obscure passwords and other sensitive personal information
that might be captured as part of the snapshot.
So, if snapshot is removed then it will directly show the new pushed view controller.
(not sure about apple guideline for snapshot)
Update:
One approach can be:
Add a black colored background on the app screen when it goes in background(in applicationDidEnterBackground method). So, it will show black screen while coming back to application.{ They store it for showing launch image for already started application.}
Where it helps?
When we delete snapshots from 'Preference' directory of application sandbox(after application goes in background) and come back to application it shows black for a while as it does not have any snapshot.
The outcome of our approach and removing snapshot are same.
Since PictureTakeVC is a view controller just use this instead
PictureTakeVC *pvc = [[PictureTakeVC alloc] initWithNibName:#"PictureTakeVC" bundle:nil];
[self.navigationController pushViewController:pvc animated:YES];
Before your app goes into background mode remove the view that is there.
Are you missing something? The didReceiveRemoteNotification fires when your application is active and running.
...but anyway if you want to achieve what you are asking you have to detect there is a pushnotification from didFinishLaunchingWithOptions (or may be from applicationDidBecomeActive or applicationWillEnterForeground) and push viewcontroller on rootviewcontroller from one of these methods.
To detect whether there were remote notification:
NSString *params = [[launchOptions objectForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"] objectForKey:#"View"];
if (params)
{
// push view
}
Use following methods to push view, you won't see any other vc when application gets activated. Let me know if any issues.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
I have done similar for push notification so let me know what are you trying to achieve exactly if I understood wrong.

Received memory warning. Level=1 when showing a UIImagePickerController

This is driving me crazy!!!
I'm getting a "Received memory warning. Level=1" whenever I attempt to show a UIImagePickerController with a sourceType = UIImagePickerControllerSourceTypeCamera.
Here is the code from my viewDidLoad where I set things up:
- (void)viewDidLoad {
[super viewDidLoad];
// Set card table green felt background
self.view.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"green_felt_bg.jpg"]];
// Init UIImagePickerController
// Instantiate a UIImagePickerController for use throughout app and set delegate
self.playerImagePicker = [[UIImagePickerController alloc] init];
self.playerImagePicker.delegate = self;
self.playerImagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
And here is how I present it modally ..
- (IBAction) addPlayers: (id)sender{
[self presentModalViewController:self.playerImagePicker animated:YES];
}
The result ... UIImagePicker starts to show and then boom ... I get the memory warning ... EVERY TIME! Interestingly enough, if I switch to sourceType = UIImagePickerControllerSourceTypePhotoLibrary ... everything works fine.
What in the heck am I missing or doing wrong? All I want to do is show the camera, take and save a picture.
FYI - I'm testing on my 3GS device.
Thanks to anyone who can help :)
This is very common. As long as you handle the memory warning without crashing and have enough space to keep going, don't let it drive you crazy.
It is not about how much memory your app has used, because it will probably happen even when you write a very simple app which have only one view with one button, clicking the button and then open camera.
I have tested on iPhone 3GS, iPad 2 and iPod touch 3G. It only happened in iPhone 3GS.
I found it will not happen anymore if you restart you device before you execute you app.
Another real solution is to comment the code, [super didReceiveMemoryWarning], in your viewController.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
After lots of test on iPhone 3GS with iOS 4.3.2, I found the logic might like that:
-> Open as much as app running on background
-> Presenting a imagePicker of UIImagePickerController, clicking "Back" or "Save" from imagePicker
-> ApplicationDelegate's method, applicationDidReceiveMemoryWarning:(UIApplication *)application, will be invoked
-> Then ViewController's method, didReceiveMemoryWarning:, will be invoked
-> Then viewDidUnload
-> Then viewDidLoad
Then you could find some views have been released and the current view has been pointed to a unexpected one.
By default, [super didReceiveMemoryWarning] will run when ViewController's didReceiveMemoryWarning method is invoked. Commenting it, and viewDidUnload: and viewDidLoad: methods will not be invoked. It means the mem warning has been totally ignored. That's what we expected.
Now after I upgraded to 4.0 it happens to my app too - before in 3.1 there were no warnings.
Actually as you said before, there should be no issue. However, this causes the view that comes after it to load again and viewDidLoad is being called. This messes up my app, since I initialize the view in viewDidLoad - now it gets initialized all over again - even though it shouldn't.
Just as a comment, this might also happen to many other apps that rely on loading the view only once!
It did happen in my app Did I Do That on iOS 4.0 too. It was not consistent, but the most common cause was creating a UIImagePickerController instance and navigating to some large photo stored in one of the albums.
Fixed by persisting state in the didReceiveMemoryWarning method, and loading from state in the viewDidLoad method. One caveat is to remember to clear the state-persisted file in the correct point for your application. For me it was leaving the relevant UIViewController under normal circumstances.
I'm getting the memory warning when opening a UIImagePickerController as well. I'm on 4.01 as well.
But in addition, the UIImagePickerController is running the close shutter animation and stalling there, with the closed shutter on screen.
It seems like the UIImagePickerController's behavior on memory warnings is to close itself.
I could dismiss the UIImagePickerController from the parent ViewController in the didReceiveMemoryWarning method, but that would make for a terrible user experience.
Has anyone seen this problem?
Is there a way to handle the memory warning so that the UIImagePickerController doesn't shut itself down?
I have been struggling with the same problem for some days now. However, resetting my iPhone 4 (clearing out memory) solves the problem so it's not really an app problem.
It appears that a level 1 or 2 memory warning triggers the UIimgPickerController delegate to offload itself. The same happens in my app with the delegate of the delegate (yes it can). After the memory warning however, it will load the delegate (and it's delegate) again causing the viewDidLoad to execute any code that's in there.
I am not sure this happens only while using the UIimgPickerController because testing all that is very time consuming.
I could write some extra code to prevent the code in viewDidLoad en viewWillAppear from execuring while showing the UIimgPickerController but that's not classy, right?
Here's food for thought: it could be
that you are running out of memory
because you are testing your app. With
some memoryleaks it is very well
possible that you are working towards
this problem every time you debug.
The UIImagePickerControllerDelegate is a memory hog because you are capturing high memory assets, be that an image or video. So from the start be sure to specify the medium capture settings, as a start point, reduce this if you don't need the quality:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.videoQuality=UIImagePickerControllerQualityTypeMedium;
Then after capturing and using these assets. Remove any temp files from the applications temp folder. Could be an extra obsessive step but its a good habit:
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:[lastCapturedFile substringFromIndex:7] ]) {
NSError *error;
// Attempt to delete the folder containing globalDel.videoPath
if ([fileManager removeItemAtPath:[lastCapturedFile substringFromIndex:7] error:&error] != YES) {
NSLog(#"Unable to delete recorded file: %#", [error localizedDescription]);
} else {
NSLog(#"deleted file");
}
}
With above it is clearing the file that was created by the delegate. In some instances if you are transcoding or creating you own assets delete the folder with that file. Note above I am removing the 'file://' part of the url string as the file manager doesn't like it:
[lastCapturedFile substringFromIndex:7]
Other things to consider are covered in the various documentation for what you are doing with that asset - transcoding, image size reduction and more. Beware that any transcoding using the AVFoundation will crash if the UIImagePickerViewController is displaying.

Problem with applicationShouldTerminate on iPhone

I'm having a problem with applicationShouldTerminate.
What ever I do it seams that has no effect. Any help would be
appreciated.
I'm well versed in programing but this just gives me headache. Im going
over some basic tutorials for xcode , as I'm new to mac in general, and am currently looking at a simple flashlight app.
It exists but I would like to add a alert box here with option not to
quit.
(void)applicationWillTerminate:(UIApplication *)application
{
[application setIdleTimerDisabled:NO];
}
this has no effect, alert is closed even before its created.
(void)applicationWillTerminate:(UIApplication *)application
{
[application setIdleTimerDisabled:NO];
UIAlertView *alertTest = [[UIAlertView alloc]
initWithTitle:#"This is a Test"
message:#"This is the message contained
with a UIAlertView"
delegate:self
cancelButtonTitle:#"Button #1"
otherButtonTitles:nil];
[alertTest addButtonWithTitle:#"Button #2"];
[alertTest show];
[alertTest autorelease];
NSLog(#"Termination");
}
I did some reading online and found that it should be possible to do
this with
(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
But no mater where I put that declaration I get error: syntax error
before NSApplicationTerminateReply.
There is no syntax error except that xcode seems not to recognize
NSApplicationTerminateReply as valid input.
Any sample code would be greatly appreciated.
I know this is a non-answer, but hopefully I can be helpful:
Displaying a "Really quit?"-type alert like this, even if you can pull it off technically (and I'm not sure you can), is a bad idea and is likely to either cause rejection from the App Store or, at best, an inconsistent user experience because no other apps do this.
The convention with iPhone apps is to save state if necessary, then yield control (for termination) as quickly as possible when the user hits the home button or switches apps.
To ensure a consistent experience, Apple probably has an aggressive timer in place to restrict what you can do in applicationWillTerminate. And even if they don't have a technical measure in place, they probably have an App Store approval policy to ensure that applications quit immediately when they're asked to.
applicationShouldTerminate and NSApplication do not exist on the iPhone. You have to use UIApplication.
The alert view is never shown because the 'show' method does not block, and therefore, the end of 'applicationWillTerminate' is reached immediately after you create the alert view and try to show it. I believe this is by design. You can't really begin asynchronous operations in 'applicationWillTerminate'.
With regards to the applicationShouldTerminate error, in case anyone's curious, NSApplicationTerminateReply and NSApplication seem to be deprecated...even though the OP's method is exactly how it appears in the docs!
Defining your method as the below should build with no errors:
-(BOOL)applicationShouldTerminate :(UIApplication *)application
I think I found the answer to what I wanted to do but will need to check it when I get back home.
Some directions were found here
http://blog.minus-zero.org/
The iPhone 2.0 software was recently released, and with it came the
ability for users to download native apps (i.e., not web sites)
directly to their phones from within the iPhone UI or via iTunes.
Developers (anyone who pays Apple 59GBP for the privilege) can then
write their own apps and have them available for purchase in the App
Store.
One limitation of the Apple-sanctioned SDK is that only one
application is allowed to be running at a time. This presents a
problem for apps such as IM clients, music players and other programs
whose functionality relies on being able to run in the background.
Another example (courtesy of James) would be an app that takes
advantage of the iPhone 3G's GPS chip to create a log of all the
places you visit.
However, there is a neat trick that I discovered: your app will only
get terminated if you switch away from it, and hitting the iPhone's
power button while your app is in the foreground doesn't count as
switching away. The upshot of this is you can create apps which
continue to run while the iPhone is in your pocket - perfect for the
GPS example.
Achieving this is as simple as implementing two methods in your
UIApplication delegate - applicationWillResignActive: and
applicationDidBecomeActive:. Here's a simple example to demonstrate
the effect.
In your UIApplication delegate header file, add a new ivar: BOOL
activeApp. Then, in your implementation, add the following three
methods:
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(#"resigning active status...");
activeApp = NO;
[self performSelector:#selector(sayHello) withObject:nil afterDelay:1.0];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"becoming the active app...");
activeApp = YES;
}
- (void)sayHello {
NSLog(#"Hello!");
if (!activeApp)
[self performSelector:#selector(sayHello) withObject:nil afterDelay:1.0];
}

iPhone: taking a picture programmatically

I'm trying to use the UIImagePickerController interface from OS 3.1, with the cameraOverlayView and takePicture, but I've clearly failed to understand how this works, and so I'm not getting the behaviour I want.
What I want to do is open the camera and take a picture automatically without having to having the user interact with the picker or edit the image. So I subclass UIImagePickerController (similar to the example in http://github.com/pmark/Helpful-iPhone-Utilities/tree/master/BTL%20Utilities/) and turn off all of the controls:
- (void)displayModalWithController:(UIViewController*)controller animated:(BOOL)animated {
self.sourceType = UIImagePickerControllerSourceTypeCamera;
self.showsCameraControls = NO;
self.navigationBarHidden = YES;
self.toolbarHidden = YES;
// Setting the overlay view up programmatically.
ipView = [[ImagePickerView alloc] init];
self.cameraOverlayView = ipView;
[controller presentModalViewController:self animated:NO];
}
In the overlayView, I've managed to force the takePicture method of UIImagePickerController to fire (I know this, because I can NSLog it, and I hear the sound of the camera taking a picture). The overlayView shows up just fine. However, the delegate method didFinishPickingMediaWithInfo: never gets called, and imagePickerControllerDidCancel doesn't get called either.
So, how do I either get the delegate methods to get called, or save the picture by overriding the takePicture method? (I have no idea how to capture the picture data here, and Google seems to have failed me). I can't help feeling that I've failed to understand how the guts of UIImagePickerController works, but the docs aren't overly helpful:
e.g.:
"You can provide a custom overlay view to display a custom picture-taking interface and you can initiate the taking of pictures from your code. Your custom overlay view can be displayed in addition to, or instead of, the default controls provided by the image picker interface."
or from showCameraControls:
"If you set this property to NO and provide your own custom controls, you can take multiple pictures before dismissing the image picker interface." - How do I dismiss the picker interface?
Note: the delegate is set properly in IB, so that's not the problem.
Thanks for any help you can provide!
I've found that you just have to wait "long enough" before calling takePicture, or it just silently fails. I don't have a good answer for how to determine the minimum value of "long enough" that will always work, but if you set a timer and wait five or ten seconds you should be okay. It would be nice if it returned some kind of an "I'm not ready to take a picture yet, sorry" error either directly from takePicture or through the delegate, but as far as I know it doesn't.
As an update to my own question: It turns out that I was trying to use takePicture too early. When I moved the action to a button on the overlay and sent takePicture from that button (once the picker was presented modally), the delegate methods fired as they should. I don't know if what I wanted is achievable - taking the image without having to press that button, automatically - but if it is, it will probably have to be done by sending takePicture sometime after I was trying to use it.
-(void)imageMethod:(id)sender{
imagePickerController = [[UIImagePickerController alloc]init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePopover=[[UIPopoverController alloc]initWithContentViewController:imagePickerController];
[imagePopover presentPopoverFromRect:importButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}