Assertion failure in -[UIActionSheet showInView:] - iphone

Anyone have any ideas what this means and how to sort it out?
* Assertion failure in -[UIActionSheet showInView:], /SourceCache/UIKit_Sim/UIKit-1912.3/UIActionSheet.m:4630 2012-03-02
17:12:34.643 Strategy & Risk[66854:15803] * Terminating app due to
uncaught exception 'NSInternalInconsistencyException', reason:
'Invalid parameter not satisfying: view != nil'
Update: It only happens sporadically:
Update 2: I don't have a tab bar or tool bar in my app
Update 3: I have changed the code to use showInView: and I get the exact same error message.
- (void)displayAddEntityActionSheet {
//Convert the tap location to this view's coordinate systems
CGRect buttonTappedRect = [self.currentNodeView convertRect:self.currentNodeView.frame toView:self.view];
UIActionSheet *actionSheet;
switch (self.currentNode.nodeType) {
case NodeTypeEntity:
actionSheet = [[[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:nil
destructiveButtonTitle:nil otherButtonTitles:#"Entity", #"Objective", nil] autorelease];
[actionSheet showFromRect:buttonTappedRect inView:self.view animated:YES];
break;
case NodeTypeObjective:
actionSheet = [[[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:nil
destructiveButtonTitle:nil otherButtonTitles:#"Risk", #"KPI", nil] autorelease];
[actionSheet showFromRect:buttonTappedRect inView:self.view animated:YES];
break;
case NodeTypeRisk:
actionSheet = [[[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:nil
destructiveButtonTitle:nil otherButtonTitles:#"KRI", #"Control", nil] autorelease];
[actionSheet showFromRect:buttonTappedRect inView:self.view animated:YES];
break;
case NodeTypeControl:
actionSheet = [[[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:nil
destructiveButtonTitle:nil otherButtonTitles:#"KCI", nil] autorelease];
[actionSheet showFromRect:buttonTappedRect inView:self.view animated:YES];
break;
default:
break;
}
}

You should use following methods for showing action sheets if you have a tab bar in your application.
[actionsheet showFromTabBar:]
or
[actionsheet showFromToolbar:]
This assertion failure you are facing is because you might be having an tab bar in your application and in iPhone you might be showing the action sheet using the method:
[actionsheet showInView:]
If that is the case then you should use:
[actionsheet showFromTabBar:]
Hope this helps you.
EDIT-2:
[actionsheet showFromBarButtonItem:self.navigationItem.rightBarButtonItem animated:YES];
EDIT-3:
UIActionSheet Crashes on iPad / not iPhone
http://forums.macrumors.com/showthread.php?t=997125

Finally discovered what was causing the error, the code below was being called several times which in turn called the method in my original post and this view controller was never being deallocated but even if it was I was not removing it as an observer for these notifications:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(addNewEntity:) name:#"addSubEntity" object:nil];
}
return self;
}
So I have fixed the bug that calls init repeatedly and for safely sake I also call removeObserver: just in case, although this view controller is re-used so it never gets called.
Moral of the story: removeObserver before deallocating!
- (void)viewDidUnload
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

You did not yet say that you made sure self.view != nil. Seems clear that's the first thing to do. Or check when you hang in the debugger.

Related

UIAlertView delegate method crashing

In my iPhone app, I have a NSObjectA class and a UIViewController B class. I want to call a instance method in B class from A. I used the following code.
Bclass *vc = [[Bclass alloc]init];
[vc hideAlert:NSString];
[vc release];
and in B class:
- (void)hideAlert:(NSString*)message{
UIAlertView *shareAlrt = [[UIAlertView alloc] initWithTitle:#""
message:message
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[shareAlrt show];
[shareAlrt release];
}
and the method called and show a AlertView. When click on the Ok button, I want to navigate to class Cclass.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
Cclass *vc = [[Cclass alloc]initWithNibName:#"Cclass" bundle:[NSBundle mainBundle]];
[self presentModalViewController:vc animated:NO];
[vc release];
}
}
But when I click on the Ok button, the app crashes. Whats happening here? I have added <UIAlertViewDelegate> in the B class.h file, but still the same error. Please help
I am getting the error code *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType alertView:clickedButtonAtIndex:]: unrecognized selector sent to instance 0x81baa80'
Just change the method
- (void)hideAlert:(NSString*)message{
UIAlertView *shareAlrt = [[UIAlertView alloc] initWithTitle:#""
message:message
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok",nil];
[shareAlrt show];
[shareAlrt release];
}
This has been answered by presuming that u have no other button except cancel button titled as "OK". Assumption is made by seeing your displayed code.
You have used Cancel button on which u cant handle delegate to perform any action.
If you look at the documentation of UIAlertViewDelegate class reference
Optionally, you can implement the alertViewCancel: method to take the
appropriate action when the system cancels your alert view. If the
delegate does not implement this method, the default behavior is to
simulate the user clicking the cancel button and closing the view.

Can not dismiss an action sheet here

A UILongPressGestureRecognizer is added to my imageView with action handleLongPressOnPhotos. The most related codes is as following:
- (IBAction)handleLongPressOnPhotos:(UILongPressGestureRecognizer *)sender
{
self.imageWillBeSaved = (UIImageView *)sender.view; //breakPoint1
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Save the photo" otherButtonTitles: #"Go to the Original photo", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view]; //breakPoint2
NSLog( #"actionSheet addr when created is %p", actionSheet );//breakPoint3
[actionSheet release];//breakPoint4
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
UIImageWriteToSavedPhotosAlbum(self.imageWillBeSaved.image, self, #selector(image: didFinishSavingWithError:contextInfo:), nil);
//[actionSheet dismissWithClickedButtonIndex:0 animated:YES]; i have tried to use this method here, but it didn't work.
break;
default:
break;
}
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error != NULL)
{
// handle error
}
else
{
// handle ok status
}
}
The action sheet will not be dismissed after i click the "save the photo" button. If i click the button again, the action sheet dismissed and the photo saved twice.Any problem in the code? Thanks in advance!
Ps. the imageView is a subview of a scrollView, and the scrollView is in a tableViewCell.
- (IBAction)handleLongPressOnPhotos:(UILongPressGestureRecognizer *)sender
{
self.imageWillBeSaved = (UIImageView *)sender.view; //breakPoint1
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Save the photo" otherButtonTitles: #"Go to the Original photo", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view]; //breakPoint2
NSLog( #"actionSheet addr when created is %p", actionSheet );//breakPoint3
[actionSheet release];//breakPoint4
}
I set two breakpoint in the "handleLongPressOnPhotos:" method as breakPoint1 and breakPoint1. I followed the steps of the code after the imageView was longPressed. The step order is :breakPoint1 -> breakPoint2 ->breakPoint1 ->breakPoint2 - > breakPoint3 -> breakPoint4 - > breakPoint3 -> breakPoint4, then went out. It is obvious that the actionSheet has been presented twice, that cause the problem. It is odd, and I do not know the reason and avoid this.
Problem solved in another question UILongPressGestureRecognizer gets called twice when pressing down
thanks to #Laddu, #MichaelDautermann, #sreecharan
IT Looks OK but please add nslog here:-
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
NSLog(#"buttonIndex.....%d",buttonIndex);
switch (buttonIndex) {
case 0:
UIImageWriteToSavedPhotosAlbum(self.imageWillBeSaved.image, self, #selector(image: didFinishSavingWithError:contextInfo:), nil);
//[actionSheet dismissWithClickedButtonIndex:0 animated:YES]; i have tried to use this method here, but it didn't work.
break;
default:
break;
}
}
Check you add ACtionSheet Delegate in .h file also .
is there a reason why you are not using actionSheet:willDismissWithButtonIndex: instead of actionSheet:clickedButtonAtIndex:.
If you use actionSheet:willDismissWithButtonIndex:, you don't need to care about dismissing the ActionSheet yourself.
Problem solved in another question UILongPressGestureRecognizer gets called twice when pressing down
thanks to #Laddu, #MichaelDautermann, #sreecharan

Why does my camera interface act weird when I use UIImagePickerController?

In my app I want the user to be able to take a picture or use one from the photo library. When the user clicks the button I made a alert view pops up at the user can choose between taking a new photo or one from the photo library. Here is the code I've used:
- (void)PictureAlert:(id)sender {
UIAlertView *AlertDialog;
// Setting up AlertDialog.
AlertDialog = [[UIAlertView alloc] initWithTitle:nil
message:nil
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Choose From Library", #"Take New Picture", nil];
[AlertDialog show]; }
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *ButtonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if ([ButtonTitle isEqualToString:#"Choose From Library"]) {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
// Pick photo.
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
} else if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
// Setting up AlertDialog.
UIAlertView *AlertDialog;
AlertDialog = [[UIAlertView alloc] initWithTitle:#"Error accessing photo library"
message:#"Device does not support a photo library"
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[AlertDialog show];
}
} else if ([ButtonTitle isEqualToString:#"Take New Picture"]) {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
// Take new photo.
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.wantsFullScreenLayout = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
} else if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
// Setting up AlertDialog.
UIAlertView *AlertDialog;
AlertDialog = [[UIAlertView alloc] initWithTitle:#"Error accessing camera"
message:#"Device does not support a camera"
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[AlertDialog show];
}
}
}
The problem is that if the user wants to take a new picture the camera interface pops up, and then if you rotate the device the interface looks like this:
And then when the user rotate it back it suddenly looks like this:
A little side problem is that the camera takes a long time to load.
Any thoughts would be appreciated :)
A few things you might want to consider:
Setting the wantsFullScreenLayout property to YES will cause the view to ignore the status bar. But since you are using the default camera controls, the status bar hides automatically. This is the most likely cause for the 20 pixel grey area on the bottom of the image.
The default camera controls are designed to be in portrait mode only. Since your first image looks like you somehow rotated the screen, you should look into your code (probably shouldAutoRotate) and see why you are rotating the view like that. This should fix the problem of the zoom you are getting in your landscape picture.
You will have memory leaks if you create a UIImagePickerController, present it, and then have no reference to it to release it later. I would recommend setting the UIImagePickerController in the interface, and setting it up in the viewDidLoad method. Try:
.h
#interface yourView:UIViewController <UIImagePickerControllerDelegate> {
UIImagePickerController * picker;
}
.m
- (void)dealloc; {
[picker release];
[super dealloc];
}
- (void)viewDidLoad; {
[super viewDidLoad];
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex; {
NSString *ButtonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if([ButtonTitle isEqualToString:#"Choose From Library"]){
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
}
else{
// Setting up AlertDialog.
UIAlertView *AlertDialog;
AlertDialog = [[UIAlertView alloc] initWithTitle:#"Error accessing camera"
message:#"Device does not support a camera"
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[AlertDialog show];
[AlertDialog release];
}
}
else if([ButtonTitle isEqualToString:#"Take New Picture"]){
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
}
else{
// Setting up AlertDialog.
UIAlertView *AlertDialog;
AlertDialog = [[UIAlertView alloc] initWithTitle:#"Error accessing camera"
message:#"Device does not support a camera"
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[AlertDialog show];
[AlertDialog release];
}
}
}
This should clean-up the memory leaks, and improve the load time. Hope that Helps!
Some time its happened if you are using a old generation iphone that have current os for example you are having iphone 3G and you update its ios to ios5 then some of the app you installed can behave differently you can check your app to another device for rectify your problem.
Make sure you set the view controller hierarchy, with mainWindow.rootViewController and [vc addChildViewController:]. This propagates orientation information down to where you need it.
It looks like for my project this was happening because you have not written the shouldAutoRotateToInterface: method in your root view controller. The rotate message propagates all the way down to the root view controller's shouldAutoRotateToInterface delegate when UIImagePickerController is called. Your method should look like this:
- (BOOL)shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
When I upgraded my project to iOS 5, I borrowed my root view controller from an iOS 3 project. iOS 3 did not automatically write this method in view controller classes Try it out and let me know.

load a different nib if phone is not connected to internet

I use Apple's Reachability class and it's working fine using an alert to tell the user that the connection is not available or the connection is lost. However, I want to change the alert to something more visual. I want to load a nib that tells the user no active connection is present but the nib is not loading. I also tried loading my other nibs but it also doesn't load the nib.
- (BOOL) checkNetworkStatus:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No Internet Connection" message:#"You are currently not connected to a WI-FI or cellular Data.\nPlease make sure you are connected." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
//NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
//[self presentModalViewController:noConn animated:NO];
//[NoConnection release];
self.isConnected = NO;
return NO;
break;
}
//more cases.........
the alert part is working just fine but the part for loading the nib is not. can you tell me whats wrong here? I'm calling this function in viewWillAppear. Thanks!
You can do the following:
if ( ! isConnected )
{
NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
[self presentModalViewController:noConn animated:NO];
[NoConnection release];
}
The code you have presented should work, sow the problem must be somewhere else probably in the nib - linking, you might have forgot to link something to the nib file.
try this
[self.navigationController presentModalViewController:noConn animated:YES];
Does your nib has NoConnection as a File's Owner (I guess NoConnection is a subclass of UIViewController, check it. I'll call this NoConnectionViewController bellow because you should name it like that for no mistake) ?
Is the file's owner view property linked with the graphical view ? Check it.
Are you working without status bar at top of the window ? That could be a problem.
Are your here inside a modalViewController ? If yes, your code won't work, you must use instead :
NoConnectionViewController* nextWindow = [[NoConnectionViewController alloc] initWithNibName:#"NoConnecton" bundle:nil]; // Check your nib name here, seems to be a mistake
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:nextWindow];
[self presentModalViewController:navController animated:YES];
[navController release];
[nextWindow release];
You need to use the delegate method of alert view
#pragma mark - AlertView Delegates
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alertView.tag == 1)
{
NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
[self presentModalViewController:noConn animated:NO];
[NoConnection release];
}
}
don't forget to assign tag value of alertView to 1.
and also dont forget to conforms to the UIAlertViewDelegate protocol
Happy Coding :)

UIActionSheet, how to dismiss it with a single click?

UIActionSheet, how to dismiss it with a single click?
I have to click a button 2 times so it gets dismissed, what should I do to make it dismissble after the first click?! Here is my code:
-(void)buttonHeld:(id)sender
{
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:#"Delete Contact?!" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Delete" otherButtonTitles: nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[popupQuery showInView:self.view];
[popupQuery release];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Delete button clicked Button Clicked");
else if (buttonIndex == 1) {
NSLog(#"Cancel Button Clicked");
}
}
Based on the name of your method "buttonHeld", my assumption is that you are trying to launch the UIActionSheet from a UILongPressGestureRecognizer. You will need to use the code listed below if you want it to work as expected. The problem stems from UILongPressGestureRecognizer being a 'continuous gesture' which fires multiple times and progresses through several different states. You'll need to monitor for the correct state and then load your UIActionSheet. I had the exact same problem and this is what solved it for me.
- (IBAction) buttonHeld:(UILongPressGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {
UIActionSheet *popupQuery = [[UIActionSheet alloc]
initWithTitle:#"Delete Contact?!"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Delete"
otherButtonTitles:nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[popupQuery showInView:self.view];
}
}
This is how i dismiss the actionsheet...
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
Hope this helps
It took me a few taps to get it to cancel as well. The problem ended up being which view I attached it to.
[action showInView:self.view];
self.view was only referenced in IB. I changed it to a different view and it worked.
No need to declare in this delegate when you alloc the actionsheet you have make cancel Button that by default dismiss the ActionSheet some thing like this
[[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:btnTitle,#"Send for a date range",nil];
from any other event you can use this method
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
In your code there is a syntax error you are putting else block in if block.
If u're developing for the iphone it's always safe to use :
[popupQuery showFromBarButtonItem:sender animated:YES]
or showFromTabBar: or showFromToolBar etc. instead of showinView.