I am using an instance of UIActivityViewController in a universal app. It works absolutely perfectly on the iPad. Nearly, but not quite on the iPhone.
I present it using:
[self presentViewController:self.activityViewController animated:YES completion:nil];
It displays the available activities correctly and if I choose one, it works. I can then tap on the Share button again and repeat with the same or a different activity as often as I like, so long as I complete the activity.
If I Cancel from the UIActivityViewController, all is well; but if I cancel from, say, Mail or Message, the next time I tap on Share, nothing happens. If I get impatient and tap again, I get the following error:
'Application tried to present modally an active controller .'
I've tried dismissing the controller before presenting it a second time, but it doesn't think it is dismissible. I've also tried presenting it from the root/navigation controller as well as the tableviewcontroller, but get the equivalent error (i.e. the app tried to present the root controller).
I see there are lots of 'odd' problems with UIActivityViewController, but I can't see anything relevant to my problem.
The problem was due to the example code I'd used. I assumed that the dismiss code was being executed, when it wasn't!
I ended up implementing UIPopoverControllerDelegate and implementing:
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
[self setPopoverActivity:nil];
}
This fixed it!
this happened to me too, i saw your answer and i didn't understand it, because that "setPopoverActivity" wasn't recognized. So i started do some changes and this solved just doing the init of the "UIActivityViewController" inside the action void instead on viewDidLoad, where it was at first place.
- (void) flipView {
self.activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:self.dataToShare
applicationActivities: nil];
self.activityViewController.excludedActivityTypes = #[UIActivityTypePrint,UIActivityTypeSaveToCameraRoll,UIActivityTypeAssignToContact, UIActivityTypeAddToReadingList];
[self presentViewController:self.activityViewController animated:YES completion:nil];
}
Hope it helps!
Related
I have a a VC structure like this
UIPageViewController -> detailViewController -> popoverviewcontroller
The popoverviewcontroller is dismissed using an unwind segue, bringing us back to the detailviewcontroller
Now, after the popover is done being dismissed, I would like to refresh the pages on the pagecontroller, since the action the user takes has changed the data.
I would also like to display an alert notifying the user about whether they were successful.
So I tried putting this code in the pageViewcontroller
- (IBAction) unwindFromPopup:(UIStoryboardSegue*)unwindSegue{
[self refreshPages];
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:#"alert" message:#"this should appear" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alertController animated:YES completion:nil];
}
I tried moving the above code to the detail view controller instead, but I am getting no result from this. No error or anything, just a complete lack of alert. I put a breakpoint in the segue, and the code gets called. But no alert.
I thought of putting the code in one of the respective viewDidAppear methods, but for some reason viewDidAppear does not get called for either the pageviewcontroller or the detailview controller after I dismiss the popup.
So at this point I have no idea how to make this alert appear.
Do I need to post my full code, or is my problem apparent with the details I've included?
Thanks - based on your comment ... long ago in a distant version of iOS I performed all the possible segues and noted what gets called when and have a table of that that I based my answer on. I must admit, nowadays I get most done using the presentation controller delegate.
Anyhow, to reply to your question, when you pop or modally present a controller, the controller that is being presented will message beingPresented and beingDismissed when it is done and you might be able to use this for what you are trying to do.
When you push a controller it will message isMovingToParentViewController when shown and isMovingFromParentViewController when dismissed, again in the controller being presented.
Back to a pop ... it will message prepareForSegue in the presenting VC and viewWillAppear and viewDidAppear in the presented VC and, when dismissing, will message only viewWillDisappear and viewDidDisappear in the presented VC, thus your problem. At least it will also message beingDismissed as mentioned and if you can use that I am really glad for you.
I have an app originally developed for iPhone, with a MapViewController as the main screen, and a Help screen and Tutorial screen both called from within a UI ActionSheet. Works fine for the iPhone.
When run on an iPad, I can't get to the Help screen and get the following runtime error:
Warning: Attempt to present <HelpViewController: 0x177076c0> on <MapViewController: 0x177d7060> which is already presenting <UIAlertController: 0x17732620>
If I add the following line of code
[self dismissViewControllerAnimated:YES completion:nil];
then I do get to the Help screen, but with the following error:
Warning: Attempt to dismiss from view controller <MapViewController: 0x17d75660> while a presentation or dismiss is in progress!
When I exit the Help screen, the MapView does not come up, however selection a new baseMap brings it back to life.
So, the code runs fine on an iPhone. On the iPad I get an error that says
1) Don't open a new view with the UIAlertController active, or
2) Don't dismiss the view, because a dismiss is already in progress...
Sure seems like a timing problem to me, I've tried both a "sleep" statement and some code to provide a short delay, neither have helped.
Anyone have any ideas?
you have to set action sheet for iPad like below..
UIActionSheet *popup = [[UIActionSheet alloc] initWithTitle:#"Some Title" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil,nil];
if(!IS_IPad){
[popup showInView:[UIApplication sharedApplication].keyWindow];
}else{
[popup showFromRect:CGRectMake((CGRectGetWidth(self.view.frame)-200)/2, self.imgLogo.frame.origin.y,200, 200) inView:self.view animated:YES];
}
Surly your action sheet working in both.
This warning comes when you are trying to present/dismiss a view with animation while another animation is still in progress. This might be because while making a selection from UIActionsheet it animates and fades away and at the same time another viewcontroller is appearing with animation. It might help if you dismiss the view controller after delay of 0.2 seconds
For some reason, when I try to open a view controller via modal segue, it opens up two of the same type. Why is this happening?
Warning: Attempt to present <ModalViewController: 0x7fa062c5edd0>
on <HomeViewController: 0x7fa062e16e40> which is already presenting
<ModalViewController: 0x7fa062fb9780>
This is causing problems because I try to use delegates, but my main view controller never gets the correct delegate.
The issue occurs when I click the the button which triggers showModalView
HomeViewController
- (IBAction)showModalView:(UIButton *)sender {
ModalViewController *modalView = [[ModalViewController alloc] init];
[self presentViewController:modalView animated:YES completion:nil];
}
I tried this solution here and here and a dozen other ones, but none seem to work for me.
Why is this happening?
The problem you're having, is because you've connected a segue to the button, and are also presenting the controller in code; you should be doing one or the other. When you removed the segue, you got a black screen because you're using alloc init to create your controller. If you made the controller in a storyboard, then you should use instantiateViewControllerWithIdentifier: instead.
However, the easier way would be to leave the segue connected to the button, and delete the code you have in the button's action method. The button doesn't need an action method, if you have it hooked directly to a segue. All of this is covered in Apple's document, "View Controller Programming Guide for iOS". You should read it.
In the IOS developer library, instructions say:
To directly control what content is being displayed, call the setViewControllers:direction:animated:completion: method
And that's what I'm trying to do, without success.
Here's what I've tried in my RootViewController.m:
NSLog(#"%s", __FUNCTION__ );
[self.pageViewController setViewControllers:
[NSArray arrayWithObjects:
[self.storyboard instantiateViewControllerWithIdentifier:
#"AlbumPageViewController4"],nil]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES completion:nil];
I know the AlbumPageViewController.m button is calling it as it displays in the NSLog. But nothing happens, no crash, no errors, no page curls. My spine location is UIPageViewControllerSpineLocationMin so I think I only need to pass it 1 view controller.
I have tried 2, but that doesn't work either.
How can I have a button that allows me to "let the user jump to a specific location in the content" just like the Docs say?
Calling a function in the RootViewController from a different class directly doesn't work. All of the self.anything are all nil.
After setting up some delegation and having the RootViewController listen and respond to the other class, the code works just fine.
I need to check if there is still a modal view over the root view controller.
The problem I am facing is that I have a second modal view coming from some thread that needs to be displayed. I want to delay the second modal view until the first one is gone.
I cannot just launch it after the first is dismissed because the second modal view is conditional.
[self.window.rootViewController presentModalViewController:vc animated:YES];
What I want to do (feel free to suggest a better alternative way):
Check if self.window.rootViewController currently has a modal view displayed on top (or is still animating modal view).
use performSelector:afterDelay:0.1
Check again, and if needed, delay again
Get rootViewController.presentedViewController (available in iOS 5.0+) or rootViewController.modalViewController (available in iOS 2.0+) and see if it's nil.
Also, you don't want to present the second view controller from the secondary thread, all UI stuff has to be done on the main thread.
I also faced this kind of problem. I wanted to pop up a modal from push and before I do that I wanted to check if some screen is already presented and if yes dismiss those and pop my screen below is the code.
// Dismiss all the modals which are currently shown.
- (void) dismissAllModalsIfAnyWithCompletion:(void(^)(BOOL success)) completion{
BOOL hiddenByModal = nil != [[UIApplication sharedApplication].keyWindow.rootViewController presentedViewController];
if (hiddenByModal) {
//We need to dismiss the existing modal and after completion pop up the new modal.
[[UIApplication sharedApplication].keyWindow.rootViewController dismissViewControllerAnimated:NO completion:^{
// After dismissing let the handler know.
completion(YES);
}];
}
else{
// If there is no modal, then simply let the handler know to pop the new modal.
completion(YES);
}
}
I'd be tempted to do something a bit more deterministic. Have one piece of code responsible for doing both modal displays and let it keep track of when the first modal appears and disappears so that, if it receives a message to display the second one, it knows whether to do it or just set a "pending" flag. When it is told that the first one has been dismissed, it can check whether a second is pending.