When and how to dismiss UIActivityViewController - ios

I create and present UIActivityViewController in my app with custom UIActivity items in it.
When I tap UIActivity icon, UIActivityViewController slides down and my modal view controller is presented. However, when I dismiss my VC, UIActivityViewController shows up.
How can I make it disappear and never shows up again when activity item is pressed?

You need to call the activityDidFinish: method on the chosen UIActivity.
From the docs for UIActivity activityDidFinish::
Discussion
This method dismisses the sharing interface provided by the UIActivityViewController object. If you provided a view controller using the activityViewController method, this method dismisses that view controller too.
You must call this method after completing the work associated with this object’s service. This is true regardless of whether you used the activityViewController or performActivity method to initiate the service. When calling the method, use the Boolean value to indicate whether the service completed successfully.

Let's say when Activity A is chosen from UIActivityVC, you want to present modal view controller M on your current view Controller C .
If you implement A's -(UIViewController*)activityViewController method, you need to call [A activityDidFinish] in your modal view controller M's dismiss method;
If you implement A's -(void) performActivity method, it's impossible to present modal view , because current view controller C is in the process of dismissing UIActivityVC .
I think the final solution is a bit tricky. My basic idea is to subclass UIActivityViewController and override -(void) viewDidDisappear method. Thus you can do whatever you like( i.e present your own modal view,or push a sequence of other view controllers) on your current view controller C.

i found this by Ethan Huang
[self presentViewController: activityController animated: YES completion:nil];
activityController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = activityController.popoverPresentationController;
popPC.barButtonItem = saveBtn;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
read all about it here :
http://getnotebox.com/developer/uiactivityviewcontroller-ios-8/

Related

ViewController does not receive a DidDismissPopover notification

I have a view controller B which is presented as a popup by another view controller A. View controller B conforms to protocol UIPopoverPresentationControllerDelegate (defined in its header file) and implements this method.
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
{
DDLogDebug(#"Clicked outside");
}
In view controller A, I initialize view controller B, set its modalPresentationStyle to UIModalPresentationPopover and present it using the method presentViewController:animated:completion:.
When I dismiss the popover by clicking next to it, I am not receiving any notification. Why is view controller B not receiving this notification?
The same thing happens when I make view controller A conform to UIPopoverPresentationControllerDelegate and implement the method there.
I am using Objective C and target for iOS 9.
EDIT
Thanks to the comments below, I found the mistake. I forgot to set the delegate. I now set the delegate in view controller A to itself, and let A retrieve the data that it needs from view controller B.
datePickerContentViewController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popoverController = [datePickerContentViewController popoverPresentationController];
popoverController.delegate = self;
[self.parentViewController presentViewController:datePickerContentViewController animated:YES completion:nil];

Some code not executing in a method called from another ViewController

My problem
I have a standard UIViewController. With the press of a button, it loads a form sheet modal view controller. When dismissing this modal view with the press of a UIBarButtonItem I call a method by doing:
ViewController *main = [[ViewController alloc] initWithNibName:nil bundle:nil];
[main updateLabel];
In the method -(void)updateLabel in the main ViewController I'm setting the text of a label, but the label won't change. But I know the function gets called, because if I do a NSLog(#"Method call test); instead of label.text = #"Test" I can see the message in console.
What am I doing wrong? It must be the way I'm calling the method in the main ViewController, because I can easily change the label anywhere else.
What I want to do:
When dismissing a modal view controller, I want a method to be called in the main view controller, and in this case change the text of a label.
Thanks for your help!
You're creating a new instance of ViewController with that code, not getting a pointer to the one you already have.
If ViewController is the controller that presented the modal view, then you can get a pointer to it with,
ViewController *main = self.presentingViewController;
A better way to do this would be to use the delegate pattern.
https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Delegation.html
The following is a design pattern suggestion
The modal view controller shouldn't know how to dismiss itself, that is the responsibility of the presenting view controller. After all, it could have been presented in many different ways (modally, popover, push navigation). Using the delegate pattern, the modal view controller would tell its delegate that it should be dismissed when the bar button item gets pressed. The delegate, which is the presenting view controller, would then dismiss the modal view and update the label mentioned in your question.

ModalView crashes in iOS7

I'm having an app crash in iOS7, but is working on iOS6. While debugging the next code from my AppDelegate, I checked that in iOS7 the next function is executed and then the modal view controller is loaded.
- (void)presentModalWebViewWithURL:(NSURL *)url title:(NSString *)title
{
[self.modalWebViewController dismissModalViewControllerAnimated:YES];
self.modalWebViewController = [[[MyModalWebViewController alloc] initWithURL:url] autorelease];
self.modalWebViewController.title = title;
UINavigationController *nav = [self.modalWebViewController modalNavigationControllerWithTarget:self dismissSelector:#selector(dismissModalWebView)];
[self.window.rootViewController presentViewController:nav animated:YES completion:NULL];
}
In iOS6, I checked that the function stops the execution in the last line until the modal view controller is loaded.
What happens in iOS7 is that when the modal view controller tries to load running viewWillAppear, I was able to check that the modal view controller has changed all the values and even the properties are pointing to objects of different types. I guess that they are being deallocated but I can't figure out why and how to fix it. Any suggestions?
When you dismiss a modal view controller, you're supposed to call the dismiss method on the view controller that presented the view controller. Also the dismissModalViewControllerAnimated: method is deprecated, you should instead use dismissViewControllerAnimated:completion:. So looking at your code, you should probably be calling the dismiss method on self.window.rootViewController, since that's what you're presenting modal views from.
Also, not knowing how the rest of your code looks, I'm assuming the first time this gets called, self.modalWebViewController is nil, so you probably want to check if self.modalWebViewController is set to something before you call dismiss, and also to set it to nil any time you do dismiss it.

How to know when a View Controller unwinds when it´s presented programmatically

I got this code that brings up the native "share" view where the user can post to facebook/twitter etc... There is a completion block, but this only get´s called when the VC shows itself, I need to know when it dismisses. Cause my app has different View Controllers for landscape / portrait mode, and I do not want to dismiss the view if the user rotates and the UIACtivityViewController is on screen.
I send a notification when the shared button is pressed to not dismiss the current view if user rotates the device. All i need now, is to know when it´s dismissed so I can reenable the function
- (IBAction)shareButtonPressed:(UIButton *)sender {
// Notify that another view is on screen to allow rotation without view disapearing.
[self sendNotificationWithName:#"landscapeViewHasPopupActive" andObject:#"empty string"];
NSString *message = #"Hello World!";
UIImage *imageToShare = [UIImage imageNamed:#"Icon.png"];
NSArray *postItems = #[message, imageToShare];
UIActivityViewController *activityVC = [[UIActivityViewController alloc]
initWithActivityItems:postItems
applicationActivities:nil];
[self presentViewController:activityVC animated:YES completion:^() {
}];
// Is showing landscape set to NO, and YES when this view disapears
}
In ios6 storyboards, there is a thing called an unwind segue. Add a method to the presenting controller to verify if unwind can/will happen. Check with google.
The same view controller that called the – presentViewController:animated:completion: method has it's counterpart: the – dismissViewControllerAnimated:completion: method.
When you want to dismiss the activityVC controller call the – dismissViewControllerAnimated:completion: method. Use the 'completion' block to execute the code you want when the view controller is dismissed.
Hope this helps!

UIActivity activityViewController being presented modally on iPad instead of in popover

When using a customer UIActivity subclass in iOS 6, it's possible to specify a custom view controller that will be displayed when your action is chosen from the initial UIActionViewController's view. You do this by returning a reference to a custom view controller from your UIActivity subclass's activityViewController method.
According to the UIActivity class reference:
activityViewController
The default implementation of this method returns nil. Subclasses that provide additional UI using a view controller can override this method to return that view controller. If this method returns a valid object, the system presents the returned view controller for you, instead of calling the performActivity method. On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.
Your custom view controller should provide a view with your custom UI and should handle any user interactions inside those views. Upon completing the activity, do not dismiss the view controller yourself. Instead, call the activityDidFinish: method and let the system dismiss it for you.
Note that bit at the end of the first paragraph: On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.
However, on iPad the view controller returned by activityViewController always displays modally, no matter how I present the UIActivityViewController (either modally or via a popover). When presenting via a popover, it causes it to crash since it doesn't think it's been dismissed.
What am I doing wrong? Is this a bug in iOS 6?
Update: here's a simple Xcode project that illustrates the problem. Feel free to clone it and play around to see if you can see where we're going wrong: github.com/simonwhitaker/GSActivityDemo
As we are talking about the UIActivityViewController, which is the view showing the available activities to the user. Apple state the following...
Your app is responsible for configuring, presenting, and dismissing this view controller. Configuration for the view controller involves specifying the data objects on which the view controller should act. (You can also specify the list of custom services your app supports.) When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
I took the last line as a sign that you have to handle how the view is presented, so I check whether the code is running on iPad and use a UIPopover accordingly. As you can sere here... https://github.com/bufferapp/buffer-uiactivity/blob/master/BufferUIActivity/Views/FirstViewController.m within the following method.
-(IBAction)openUIActivityView:(id)sender {
NSString *text = #"Hello world";
NSString *url = #"http://bufferapp.com";
NSArray *activityItems = #[text, url];
BufferUIActivity *bufferActivity = [[BufferUIActivity alloc] init];
UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:#[ bufferActivity ]];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityView animated:YES completion:^{
}];
} else {
// Change Rect to position Popover
self.popup = [[UIPopoverController alloc] initWithContentViewController:activityView];
[self.popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.width/2, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
I think the issue with the activity view controller not showing in a popover is a bug and the docs reflect the correct intent. However, I don’t know of a way to workaround this atm.
The part about dismissing the view controller, however, is a different issue. You are not supposed to dismiss the view controller that you return from -[UIActivity activityViewController], but you are responsible for dismissing the popover that you have presented, which in turn will also remove your custom view controller from the hierarchy. (And because it works this way, I’m inclined to believe that the custom view controller would normally have to be shown in the popover.)
Here’s an example with code from your example app:
UIActivityViewController *vc = [[UIActivityViewController alloc] initWithActivityItems:activityItems
applicationActivities:applicationActivities];
vc.completionHandler = ^(NSString *activityType, BOOL completed){
[self.activityPopoverController dismissPopoverAnimated:YES];
};
I had the same problem in iOS 7. The solution to show the custom view in the popover is to create and show it in the -(void)performActivity method instead of returning it in -(UIViewController *)activityViewController.
You can see example code in my question/answer under this link:
iOS 7 custom UIActivity as popover
I just had the same problem but solved it by setting the ViewController to:
[yourViewController setModalPresentationStyle:UIModalPresentationPageSheet];
in
- (UIViewController *)activityViewController
hope this helps

Resources