SLComposeViewController - "Attempt to present" errors in iOS 8 - ios

Updating some code for iOS 8. I ran into this error on an iPad only app which worked flawlessly in iOS 7. I'm using a UIActionSheet to present options of share options, Facebook and Twitter are giving me heck.
SLComposeViewController *facebookShare = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
//I add an image if there is one
//I set some initial text
[self presentViewController:facebookShare animated:YES completion:nil];
Pretty straight forward stuff. But on iOS 8 I get the below
Warning: Attempt to present SLComposeViewController: 0x1a238760> on
PostDetailViewController: 0x180c5200> which is already presenting
(null)
I've seen this error below and I get what its all about. However its saying my PostDetailViewController is already presenting (null)?!? So basically its already busy with nothing?
I've attempted to present the SLComposeViewController from other VC's in the hearty but I keep getting the Attempt to present error. I've tried presenting from
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController , and self.navigationController to no avail. I've also tried pushing the SLComposeViewController from self.navigationController which actually works but gives undesired results as it pushes an empty background then stays there until SLComposeViewController is closed and the user presses back.
Any leads would be great! Thanks in advance.
EDIT 1:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0)[self shareWithTwitter];
if (buttonIndex == 1)[self shareWithFacebook];
if (buttonIndex == 2)[self shareWithiMessage];
if (buttonIndex == 3)[self shareWithEmail];
if (buttonIndex == 4)[self SaveImageToCameraRoll];
}
-(void)shareWithFacebook{
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
//add animal URL
SLComposeViewController *facebookShare = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[facebookShare addURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.somelink.com/detail.aspx?id=%#",theAnimal.AnimalID]]];
//add image if there is one
if (theAnimal.PhotoUrl) {
[facebookShare addImage:imageView1.image];
}
//set initial text
if ([theAnimal.Sex isEqualToString:#"Male"]) {
[facebookShare setInitialText:[NSString stringWithFormat:NSLocalizedString(#"pop_his_fb_share", nil),theAnimal.Name]];
}else [facebookShare setInitialText:[NSString stringWithFormat:NSLocalizedString(#"pop_her_fb_share", nil),theAnimal.Name]];
[self presentViewController:facebookShare animated:YES completion:nil];
} else {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:[NSString stringWithFormat:NSLocalizedString(#"alert", nil)] message:[NSString stringWithFormat:NSLocalizedString(#"details_no_fb_account", nil)] delegate:nil cancelButtonTitle:[NSString stringWithFormat:NSLocalizedString(#"dismiss", nil)] otherButtonTitles:nil, nil];
[alert show];
}
}

I found out that in iOS 8 ActionSheet is actually considered a ViewController (at least I didn't know if it was before), hence the error message. The ActionSheet is attempting to be dismissed when a button is clicked on the delegate method I was using:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
This delegate gets me the button index on click however the ActionSheet is still visible. When a click occurs the presenting ViewController attempts to dismiss the ActionSheet and I get my error.
I switched to:
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
(Note: didDismiss) So my sharing methods are not called until the presenting ViewController has dismissed the ActionSheet, then it is free to present the share ViewController!
Hope this helps someone else. Cheers!

Just try following thing.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self presentViewController:fbViewController animated:YES completion:nil];
}];

Related

UIActionSheet block view controller dealloc

When in my View controller I touch on a button launch this simple code
- (IBAction)tapOnButton:(UIButton *)sender
{
UIActionSheet *act = [[UIActionSheet alloc] initWithTitle:#"test" delegate:self cancelButtonTitle:#"aa" destructiveButtonTitle:#"bb" otherButtonTitles:#"cc", nil];
[act showFromRect:CGRectMake(50, 50, 100, 100) inView:self.view animated:YES];
}
-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
}
}
I get a Actionsheet on screen, tap on any button of the Actionsheet and this closes.
When I run dismiss my viewcontroller is not performed dealloc .
If you do not touch the button and do not open the actionsheet the dealloc works .
is a big enough problem. Someone 's going on?
i'm on ios 8.1.3
I am experiencing the same problem using the deprecated UIActionSheet in iOS 8 iPad. Using iPhone (iOS 7 and iOS 8) and iOS 7 iPad, the problem cannot be reproduced.
The only solution right now that I have tested to be working is to use UIAlertController to present action sheets in iOS 8. If you use UIAlertController, the View Controller gets deallocated correctly.
Most likely some references are retained to the view controller - hence it is not being deallocated.
Please try setting the delegate explicitly to nil in the delegate method like below:
- (IBAction)tapOnButton:(UIButton *)sender
{
UIActionSheet *act = [[UIActionSheet alloc] initWithTitle:#"test" delegate:self cancelButtonTitle:#"aa" destructiveButtonTitle:#"bb" otherButtonTitles:#"cc", nil];
[act showFromRect:CGRectMake(50, 50, 100, 100) inView:self.view animated:YES];
}
-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
}
actionSheet.delegate = nil
}

iOS - segue from alert view is not being called

I have a segue that I want to be preformed when I push the Manual Entry and Scan Tag buttons on my AlertView.
#implementation triageViewController
- (IBAction)addNew:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add A New Entry"
message:#"Choose a way to add a new entry."
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Manual Entry", #"Scan Tag", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != alertView.firstOtherButtonIndex) {
[self performSegueWithIdentifier:#"manual" sender: self];
}
if (buttonIndex != alertView.cancelButtonIndex) {
[self performSegueWithIdentifier:#"scan" sender: self];
}
}
(I realize this would probably make the cancel button preform a segue right now, but i'm more concerned with making it work)
I have the two segues in my storyboard, going from a UITabViewController to two different UIViewControllers. neither of these are being called, so when I tap them. I tried using both push and modal segues, but neither one was working.
I also tried the if/else statement like so:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self performSegueWithIdentifier:#"manual" sender: self];
}
if (buttonIndex == 1) {
[self performSegueWithIdentifier:#"scan" sender: self];
}
}
But this is not working either.
Could someone help me figure out what is going wrong? Again in case I was unclear, I want to preform a segue from a UIAlertView pop-up located on a UITabBarController to two separate UIViewControllers.
Thanks
It looks like your UIAlertView has a delegate of nil so your function is never being called. Set that to self and then in your view controller's header make sure you're implementing the UIAlertViewDelegate protocol.

UIAlertView crash issue on another view controller

I have 2 view controllers, ViewController 1(VC1) and 2(VC2). In VC2 I have a back and done button. On clicking back button it goes directly to VC1 and on done it makes an api call and when it gets a response it shows an alert view and clicking ok goes back to VC1. Now when I make a api call a loading bar shows up and disappears when I get response and shows the AlertView. But if during that fraction of second when the loading disappears and AlertView is going to be popped up if I click on back and the view changes to VC1, the alert appears on VC1 and results in a crash.
This is a rare case as no user will purposely try for it but I was wondering if that crash can be managed without disabling the back button. I think there can be other instance such cases like if we are making an asynchronous calls and if the user is allowed to use UI while waiting for response and if any error alert that was suppose to show on one ViewController shows up in another may result in crash since the delegate that alert is referring to is that of the previous view controller. So is there any way to handle this kind of crash efficiently?
//Alert View sample
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[alert setTag:701];
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView tag] == 701)
if (buttonIndex == 0)
{
[self.navigationController popViewControllerAnimated:YES];
}
}
The proper way to fix this problem is to use an instance variable to keep a reference to the alert view.
This instance variable should be set to nil in the alertView:didDismissWithButtonIndex: delegate method.
In the view controller's dealloc method, you call dismissWithClickedButtonIndex:animated: if the instance variable is still set.
Assume _alertView is the instance variable.
Create the alert:
_alertView = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[_alertView setTag:701];
[_alertView show];
Update your existing alertView:clickedButtonAtIndex: method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([alertView tag] == 701) {
_alertView.delegate = nil;
_alertView = nil;
if (buttonIndex == 0) {
[self.navigationController popViewControllerAnimated:YES];
}
}
}
Add:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
_alertView = nil;
}
Add:
- (void)dealloc {
if (_alertView) {
_alertView.delegate = nil;
[_alertView dismissWithClickedButtonIndex:_alertView.cancelButtonIndex animated:NO];
_alertView = nil;
}
}

Segue after pressing a button in UIAlertView

I'm developing an app in which I need to show a ViewController when I press the "OK" button in an UIAlertView. How I can do that?
I found on here this solution: iOS Dev: Segue by pressing a button in an Alert?, but it didn't work.
xCode says:
the method: presentModalViewController is deprecated
and I found on the web that I should use the method presentViewController.
I tried to do that but it shows me a black screen without any interaction, what's wrong?
I paste here my code, maybe you can help me.
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != alertView.cancelButtonIndex)
{
PromoViewController *pvc = [[PromoViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
}
Thank you
In order to use a segue programatically you need to called performSegueWithIdentifier.
First make sure your segue has an identifier in the storyboard.
Then use this code instead...
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != alertView.cancelButtonIndex)
{
[self performSegueWithIdentifier:#"YourSegueIdentifier"];
}
}
This will do what you want.
See this: Make button it UIAlertView perform Segue
It will show you how to create a manual segue and call it.
Well another approach is to get the instance and do it programatically as
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
PromoViewController *controller = (PromoViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"<Controller ID>"];
[self presentViewController:controller animated:YES completion:nil];
Note controller ID is the storyboard id you set for the scene via attribute inspector

What is wrong with my code trying to react to Popup Button [duplicate]

This question already has an answer here:
UIAlertView not functioning correctly
(1 answer)
Closed 8 years ago.
I am trying to make a popup appear when the user clicks a button with a warning, and if they click cancel, it will be dismissed, but if they click continue, I want it to present the view controller. Here is my code, but it only dismisses the popup no matter which button I press:
- (IBAction)latest:(id)sender {
alert = [[UIAlertView alloc] initWithTitle:#"WARNING" message:#"Continuing will use internet and may cause app to slow down in large crowds" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Continue", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 2) {
UIViewController *NVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Latest"];
[self presentViewController:NVC animated:YES completion:Nil];
}
}
Your problem is simple - you need to pass self as the alert view's delegate, not nil.
Also, in your delegate method, don't hard code button indexes. Do this instead:
if (buttonIndex == alertView.firstOtherButtonIndex) {
}
You only have 2 options to click. Indexes start at 0 not 1 so change if (buttonIndex == 2) to if (buttonIndex == 1)
Ok I figured it out. I had to set the delegate to self, it was set to "nil".

Resources