This question already has answers here:
dismiss share extension custom viewcontroller
(2 answers)
Closed 4 years ago.
So I have an app and a share extension. For the share extension I have just one simple controller that extends UIViewController and not SLComposeServiceViewController (I believe the default view is too complicated for what I am trying to do). What i'm trying to achieve inside the extension is to get some data from UserDefaults, make some HTTP requests and show an alert with the HTTP response. The share extension should only be used inside a browser, but after I tap the extension the browser view freezes and after I dismiss the alert the browser is still frozen. How and where I should dismiss the alert or the parent view?
I'm new to this environment but I did some research and I believe this has something to do with the view hierarchy but I'm not sure, here is the controller:
class ShareViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
}
override func viewDidAppear(_ animated: Bool) {
let alert = UIAlertController(title: "Notification", message: "message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
It's a duplicate and I'm not sure if I should answer here as well. Sorry for not searching enough. For swift 3:
self.extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
Related
I have a ViewControllerA that already show as pop out,which is present modally. Inside this ViewControllerA have a tableview with tableViewCell .So in each cell have a button.When users click on this button,I want to show actionSheet at the bottom of the screen.
Here is my code:
TableViewCell class,here I connect the button to the IBAction
protocol MyDelegate: class {
func showDropDownMenu()
}
class tableCell: UITableViewCell {
weak var delegate: MyDelegate?
#IBAction func dropDownButton(_ sender: Any) {
print("print something")
self.delegate?.showDropDownMenu()
}
}
ViewControllerA
class ViewControllerA: UIViewController , UITableViewDataSource, UITableViewDelegate,MyDelegate {
func showDropDownMenu() {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// Create your actions - take a look at different style attributes
let hideAction = UIAlertAction(title: "Hide", style: .default) { (action) in
print("didPress hide")
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print("didPress cancel")
}
actionSheet.addAction(hideAction)
actionSheet.addAction(cancelAction)
self.present(actionSheet, animated: true, completion: nil)
}
Suppose when click on the button will call the function showDropDownMenu() in ViewControllerA.Now I click on dropDownButton it will show print something in console(means no problem with the button),but the actionSheet not show up on the bottom.
I not sure what is the problem here,but I suspect is cause by ViewControllerA is present using segue with properties like so:
Kind: Present modally ,Presentation: Over Current Context ,Transition:
Cover Vertical
If this is the reason,please help me how to present an actionsheet from a View Controller that presented modally. Thank you
Code for showing ViewControllerA :
func showViewControllerA(Id: Int) {
self.performSegue(withIdentifier: "showViewControllerA", sender: Id)
}
Refer this link. Though it's for IPad, it will give you a brief idea of where and how to present the action sheet
https://medium.com/#nickmeehan/actionsheet-popover-on-ipad-in-swift-5768dfa82094
I have faced a similar scenario of what you are trying to achive, and this solution which i provided above helped me out. Hope, it helps you out as Well.
Make sure you have set value for delegate. For example
cell.delegate = self;
I am using Swift 3, Xcode 8.2.
I have an application where the user launches the iPhone camera and I give them a popup with instructions on how to take a good picture. I want there to be a way to create pages within the UIAlertController. I did a quick sketch of what I want to achieve.
Code wise, I am not sure what to do:
func displayInstructions() {
let insController = UIAlertController(title: "Instructions", message: "Step 1: Do this.", preferredStyle: .alert)
let actionDone = UIAlertAction(title: "OK", style: .cancel) { (action:UIAlertAction) in
//This is called when the user presses the cancel button.
print("You've pressed the done button");
}
//Add the buttons
errorController.addAction(actionDone)
// Some way to addSubviews here??
let pageViewController: UIPageViewController
insController.addSubview(pageViewController)
//Present the instruction controller
self.present(insController, animated: true, completion: nil)
}
Any help would be greatly appreciated. Thank you!
There is a property on UIAlertController, not advertised in public API but that seem usable without trouble going through the app store review. So, using KVC, you can set the contentViewController of the alert controller.
let pageViewController: UIPageViewController
// configure pageViewController...
insController.setValue(pageViewController, forKey: "contentViewController")
You can also set the size of the contentViewController by setting preferredContentSize.height on it
pageViewController.preferredContentSize.height = 180
This is what the result looks like with an empty page view controller
I am building a Swift 3 app with the following Storyboard:
On the left (in green) is a UIPageViewController that holds the 2 NavigationController as 2 pages. This allows the user to swipe between 2 subparts of the app.
The problem is the following. I'm trying to display an alert in tha black UIViewController.
Here is the code to display the alert:
override func viewDidAppear(_ animated: Bool) {
let alert = UIAlertController(title: "Hello", message: "World", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { action in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
It works but I always get the the below warning:
Presenting view controllers on detached view controllers is discouraged
I also tried with DispatchQueue.main.async to present the view but I ran into the same warning.
However what I found is, if I set the NavigationController (bottom one) as the initial view controller, it works without the warning.
So, does using a UIPageViewController mean the pages will be kind of detached ?
What am I missing here ? Do I forgot to link stuff ?
You can try following.
[self.view.window.rootViewController presentViewController:alert animated:YES completion:nil];
When you are done you can dismiss it.
[self dismissViewControllerAnimated:YES completion:nil];
Let me know if this works.
I want to display a UIAlertController whenever user opens the application.
This is how I'm creating and trying to show it:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//simple alert dialog
let alert=UIAlertController(title: "Alert 1", message: "One is awesome", preferredStyle: UIAlertControllerStyle.Alert);
//show it
showViewController(alert, sender: self);
}
}
Why is it not being displayed?
It will work if you'd use: presentViewController(alert, animated: true, completion: nil)
As #matt stated, it’s better to present your alertViewController in ViewDidAppear instead of ViewDidLoad, because than the presenting viewController is in the interface.
Too soon. In viewDidLoad, your view is not even in the interface yet! There is nothing to show from.
I perform a segue from scene 1 to scene 2. I then return from scene 2 to scene 1. How do I not only pass data from scene 2 to scene 1 but detect in scene 1 that I've returned from scene 2 and execute code in scene 1?
In Android I do this with startActivity and onActivityResult.
Introducing Bool state like the other answer's suggesting is very bad and must be avoided if possible as it greatly increases the complexity of your app.
Amongst many other patterns, easiest one to solve this kind of problem is by passing delegate object to Controller2.
protocol Controller2Delegate {
func controller2DidReturn()
}
class Controller1: Controller2Delegate {
func controller2DidReturn() {
// your code.
}
func prepareForSegue(...) {
// get controller2 instance
controller2.delegate = self
}
}
class Controller2 {
var delegate: Controller2Delegate!
func done() {
// dismiss viewcontroller
delegate.controller2DidReturn()
}
}
States are evil and is the single biggest source of software bugs.
you could do it like this:
class SourceViewController: UIViewController {
var didReturnFromDestinationViewController = false
#IBAction func returnToSourceViewController(segue: UIStoryboardSegue) {
didReturnFromDestinationViewController = true
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if didReturnFromDestinationViewController == true {
// reset the value
didReturnFromDestinationViewController = false
// do whatever you want
}
}
}
The problem I was having was that I was trying to show an alert dialog after the unwind segue had finished. So my View Controller 2 performed an unwind segue to View Controller 1. What I found is that the code that runs after the unwind segue method is called runs before View Controller 2 is dismissed, so when I tried to show an alert dialog, it would disappear as soon as View Controller 2 was dismissed.
If the other solutions don't work for you, do what I did. I added a viewWillAppear override to my class and dismissed the parent controller there, then added the code for my alert dialog after that. To make sure viewWillAppear wasn't showing the alert dialog the first time View Controller 1 was presented, I set up an if statement checking for the name of a variable that I declared in the class and had set equal to "". Then in View Controller 2 I passed some text in the variable back to View Controller 1, so when the if statement runs it tests the variable not equal to "", and when it finds it's not, the code is run. In my case the variable was named "firstname".
override func viewWillAppear(_ animated: Bool) {
if firstname != "" {
self.parent?.dismiss(animated: true, completion: nil)
//CustomViewController?.dismiss(animated: true, completion: nil)
let alertController = UIAlertController(title: "Hello", message: "This is a test", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Close Alert", style: .default, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
}