How to present UIAlertView from appDelegate - ios

I m trying to display a UIAlertView from the appDelegate in
didReceiveRemoteNotification
when the app receive a push notification.
I ve this error :
Warning: Attempt to present <UIAlertController: 0x14c5494c0> on <UINavigationController:
0x14c60ce00> whose view is not in the window hierarchy!
here is my code :
func application(application: UIApplication, didReceiveRemoteNotification userInfo: NSDictionary) {
var contentPush: NSDictionary = userInfo.objectForKey("aps") as NSDictionary
var message = contentPush.objectForKey("alert") as String
let alertController = UIAlertController(title: "Default Style", message: message, preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
let photoPushedVc = self.storyboard.instantiateViewControllerWithIdentifier("CommentTableViewController") as CommentTableViewController
println("the fetched post is \(post)")
photoPushedVc.post = post
let activeVc = UIApplication.sharedApplication().keyWindow?.rootViewController
activeVc?.presentViewController(photoPushedVc, animated: true, completion: nil)
}
alertController.addAction(OKAction)
let activeVc = UIApplication.sharedApplication().keyWindow?.rootViewController
activeVc?.presentViewController(alertController, animated: true, completion: nil)}

To generate AlertController Dialog Box from AppDelegate using Objective-C,
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Title" message:#"Hello World!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:ok];
Type 1
UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
alertWindow.rootViewController = [[UIViewController alloc] init];
alertWindow.windowLevel = UIWindowLevelAlert + 1;
[alertWindow makeKeyAndVisible];
[alertWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
Type 2
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
[topController presentViewController:alertController animated:YES completion:nil];
Both are tested and working fine.

Ok i finally got it, you need to find the active VC using this before trying to present your alertController :
let navigationController = application.windows[0].rootViewController as UINavigationController
let activeViewCont = navigationController.visibleViewController
activeViewCont.presentViewController(alertController, animated: true, completion: nil)

Here is mine Swift 3.0 example
func showTopLevelAlert() {
let alertController = UIAlertController (title: "title", message: "message.", preferredStyle: .alert)
let firstAction = UIAlertAction(title: "First", style: .default, handler: nil)
alertController.addAction(firstAction)
let cancelAction = UIAlertAction(title: "Отмена", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
Hope it helps to someone

If you need the same in Objective-c
UIAlertController *alertvc = [UIAlertController alertControllerWithTitle:#"Alert Title..!!" message:#"Hey! Alert body come here." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOk = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alertvc addAction:actionOk];
If you have navigation based app:
UINavigationController *nvc = (UINavigationController *)[[application windows] objectAtIndex:0].rootViewController;
UIViewController *vc = nvc.visibleViewController;
[vc presentViewController:alertvc animated:YES completion:nil];
If you have single view based app:
UIViewController *vc = self.window.rootViewController;
[vc presentViewController:alertvc animated:YES completion:nil];

how i did it
func showAlertAppDelegate(title : String,message : String,buttonTitle : String,window: UIWindow){
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: buttonTitle, style: UIAlertActionStyle.Default, handler: nil))
window.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
Use Example
self.showAlertAppDelegate(title: "Alert",message: "Opened From AppDelegate",buttonTitle: "ok",window: self.window!);
Download Example With Source Code

I use an UIViewController extension to get the current visible view controller (see: How to get visible viewController from app delegate when using storyboard?).
and then present the alert controller:
let visibleVC = UIApplication.sharedApplication().keyWindow?.rootViewController?.visibleViewController
visibleVC!.presentViewController(alertController, animated: true, completion: nil)

To show alert on top controller from app delegate
var topController : UIViewController = (application.keyWindow?.rootViewController)!
while ((topController.presentedViewController) != nil) {
topController = topController.presentedViewController!
}
//showAlertInViewController func is in UIAlertController Extension
UIAlertController.showAlertInViewController(topController, withMessage: messageString, title: titleString)
Add extension in UIAlertController
static func showAlertInViewController(viewController: UIViewController?, withMessage message: String, title: String) {
let myAlert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
myAlert.addAction(UIAlertAction(title: NSLocalizedString("Ok", comment: ""), style: .Default, handler: { (action: UIAlertAction!) in
print("Handle Ok logic here")
// Let the alert simply dismiss for now
}))
viewController?.presentViewController(myAlert, animated: true, completion: nil)
}

Related

alerting user to push when app is open [duplicate]

I'm working with PushNotification on iOS app. I would like to show a UIalertcontroller when the app receive a notification.
I try this code below in the AppDelegate:
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
But the UIAlertcontroller is showing in the root View (First screen) and for other uiviewcontroller i got warning or the app crashes.
try this
Objective-C
UIWindow* topWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
topWindow.rootViewController = [UIViewController new];
topWindow.windowLevel = UIWindowLevelAlert + 1;
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"APNS" message:#"received Notification" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(#"OK",#"confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.hidden = YES; // if you want to hide the topwindow then use this
topWindow = nil; // if you want to remove the topwindow then use this
}]];
[topWindow makeKeyAndVisible];
[topWindow.rootViewController presentViewController:alert animated:YES completion:nil];
Swift3 and above
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindow.Level.alert + 1
let alert = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow?.isHidden = true // if you want to hide the topwindow then use this
topWindow = nil // if you want to hide the topwindow then use this
})
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion: nil)
Detail description: http://www.thecave.com/2015/09/28/how-to-present-an-alert-view-using-uialertcontroller-when-you-dont-have-a-view-controller/
Shortest & Simplest :
Create a extension :
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)
}
return controller
} }
and then use it anywhere like
UIApplication.topViewController()?.present(UIViewController, animated: true, completion: nil)
With this you can present Alert or anything Anywhere
Example :
let alert = UIAlertController(title: "Your title", message: "Your message", preferredStyle: .alert)
let cancelButton = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(cancelButton)
UIApplication.topViewController()?.present(alert, animated: true, completion: nil)
ALTERNATE METHOD :
No need to create any Extension or any method or anything simply write the above 3 lines for creating an Alert and for presenting use :
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
That's it.! =)
Anbu.Karthik's answer but in
Swift 4.1
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindowLevelAlert + 1
let alert: UIAlertController = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: { (alertAction) in
topWindow?.isHidden = true
topWindow = nil
}))
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion:nil)
Thanks for reading this.
Swift 4.1
You can use the following code to present alert from AppDelegate
func showAlertFromAppDelegates(){
let alertVC = UIAlertController(title: "Oops" , message: "Presented Alert from AppDelegates", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.cancel) { (alert) in
exit(0) // Your code here
}
alertVC.addAction(okAction)
DispatchQueue.main.async {
var presentVC = self.window?.rootViewController
while let next = presentVC?.presentedViewController {
presentVC = next
}
presentVC?.present(alertVC, animated: true, completion: nil)
}
}
For the easiness, I used category
UIAlertController+UIWindow.h
#interface UIAlertController (UIWindow)
- (void)show;
- (void)show:(BOOL)animated;
#end
UIAlertController+UIWindow.m
#import <objc/runtime.h>
#interface UIAlertController (Private)
#property (nonatomic, strong) UIWindow *alertWindow;
#end
#implementation UIAlertController (Private)
#dynamic alertWindow;
- (void)setAlertWindow:(UIWindow *)alertWindow {
objc_setAssociatedObject(self, #selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIWindow *)alertWindow {
return objc_getAssociatedObject(self, #selector(alertWindow));
}
#end
#implementation UIAlertController (UIWindow)
- (void)show {
[self show:YES];
}
- (void)show:(BOOL)animated {
[self setupWindow];
[self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
}
- (void)setupWindow {
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
if ([delegate respondsToSelector:#selector(window)]) {
self.alertWindow.tintColor = delegate.window.tintColor;
}
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// precaution to insure window gets destroyed
self.alertWindow.hidden = YES;
self.alertWindow = nil;
}
Use:
UIAlertController *alertController;
// -- code --
[alertController show];
I have written a static class to make code reusable in swift 4, This class provied different methods for showing alerts.
class AlertUtility: NSObject {
static func showAlert(title: String!, message : String!, viewController: UIViewController) {
let alert = UIAlertController(title: title, message: message ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertAutoDismiss(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 0.8
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
topWindow.isHidden = true
}
}
// Show alert view with call back
static func showAlertWithCB(title: String, message: String, isConditional: Bool, viewController: UIViewController, completionBlock: #escaping (_: Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
// Check whether it's conditional or not ('YES' 'NO, or just 'OK')
if isConditional
{
alert.addAction(UIAlertAction(title: NSLocalizedString("yes", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("no", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(false)
}))
}
else
{
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
viewController.present(alert, animated: true, completion: nil)
}
static func showAlert(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 1
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: {(_ action: UIAlertAction) -> Void in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.isHidden = true
}))
}
static func showComingSoon(viewController: UIViewController) {
let alert = UIAlertController(title: "", message: "Coming Soon", preferredStyle: .alert)
viewController.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 1 seconds)
let when = DispatchTime.now() + 0.6
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
}
}
static func showGenericErrorMessageAlert(viewController: UIViewController) {
let alert = UIAlertController(title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("generic.error.message", comment: "") ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertWithTextField(viewController : UIViewController,completionBlock: #escaping (_: Bool, String) -> Void) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Report Event?", message: "", preferredStyle: .alert)
alert.view.tintColor = APP_ORANGE_COLOR
//2. Add the text field. You can configure it however you need.
//AlertUtility.addte
alert.addTextField { (textField) in
let heightConstraint = NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
textField.addConstraint(heightConstraint)
textField.placeholder = "Enter report reason here"
textField.tintColor = APP_ORANGE_COLOR
textField.autocapitalizationType = .sentences
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
// Force unwrapping because we know it exists.
completionBlock(true,"")
//print("Text field: \(textField.text)")
}))
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Submit", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
completionBlock(true,(textField?.text)!)
//print("Text field: \(textField.text)")
}))
// 4. Present the alert.
viewController.present(alert, animated: true, completion: nil)
let textField = alert.textFields![0]
let v = UIView.init(frame: textField.frame)
textField.addSubview(v)
v.frame = textField.frame
v.bounds = textField.bounds
v.backgroundColor = APP_ORANGE_COLOR
v.superview?.bringSubview(toFront: v)
}
}

IPad Simulator fine but IPad crashes app when uploading image using WKWebview

Background & Short Summary
I am using WkWebview in order to show web pages for my app. I have it so that you can choose an image from camera or photo library. However there seems to be an issue with the app crashing on selecting the image.
Specs
I am running on IOS 10.0.2 on Tablet , and IOS 10.0 on the simulator using Swift 3. I am running both from XCode 8.
On the simulator I am getting an "error" when trying to upload images
I get the following message:
2016-10-19 02:15:36.150670 z4[31561:14708540] [Generic]
Creating an image format with an unknown type is an error
The image is fine and I am able to use it for upload. This behavior I thought was weird but I read that it has to do with memory management on IOS
On the tablet itself I get the following
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Your application has presented a
UIAlertController (<UIAlertController: 0x151e80350>)
of style UIAlertControllerStyleActionSheet.
The modalPresentationStyle of a UIAlertController
with this style is UIModalPresentationPopover.
You must provide location information for this
popover through the alert controller's popoverPresentationController.
You must provide either a sourceView and sourceRect or a barButtonItem.
If this information is not known when you present the alert controller,
you may provide it in the UIPopoverPresentationControllerDelegate method
-prepareForPopoverPresentation.'
The app seems to crash in the AppDelegate. I have no idea how to do their recommendations. I also don't know if this is part of a deeper issue, or if I am missing something really simple.
Code that I have related to UIAlerts
The following are 3 functions I have related to UIAlertController
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping () -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
completionHandler()
}))
self.popoverPresentationController?.sourceView = self.view
self.popoverPresentationController?.sourceRect = self.view.bounds
self.present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping (Bool) -> Void) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action) in
completionHandler(true)
}))
alertController.addAction(UIAlertAction(title: "No", style: .default, handler: { (action) in
completionHandler(false)
}))
self.popoverPresentationController?.sourceView = self.view
self.popoverPresentationController?.sourceRect = self.view.bounds
self.present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping (String?) -> Void) {
let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)
alertController.addTextField { (textField) in
textField.text = defaultText
}
alertController.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action) in
if let text = alertController.textFields?.first?.text {
completionHandler(text)
} else {
completionHandler(defaultText)
}
}))
alertController.addAction(UIAlertAction(title: "No", style: .default, handler: { (action) in
completionHandler(nil)
}))
self.popoverPresentationController?.sourceView = self.view
self.popoverPresentationController?.sourceRect = self.view.bounds
self.present(alertController, animated: true, completion: nil)
}
How can I handle this exception and fix this problem so my app doesn't crash on me? I can provide more details and code if needed. Thank you for your help in advance.
You have to do small changes in your code to work in iPad. I am adding the missing line of your code.
self.popoverPresentationController = alertController.popoverPresentationController
alertController.modalPresentationStyle = .Popover
Add these two lines of code in your 3 functions.
Please use below Objective-C code as reference. So it may be work for you.
- (void)showAlertWithTitle:(NSString *)title withMessage:(NSString *)message withStyle:(UIAlertControllerStyle) alertStyle andActions:(NSArray *)actions andSource:(UIView *)sourceView{
UIAlertController *alertController= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:alertStyle];
for (UIAlertAction *action in actions) {
[alertController addAction:action];
}
UIWindow *alertWindow = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
alertWindow.rootViewController = [[UIViewController alloc]init];
alertWindow.windowLevel = UIWindowLevelAlert + 1;
[alertWindow makeKeyAndVisible];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[alertController setModalPresentationStyle:UIModalPresentationPopover];
UIPopoverPresentationController *popPresenter = [alertController
popoverPresentationController];
popPresenter.sourceView = sourceView;
popPresenter.sourceRect = sourceView.bounds;
}
[alertWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
- (void)dismissAlertController{
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
[topWindow.rootViewController dismissViewControllerAnimated:YES completion: nil];}
To use above methods, Here is the sample.
__weak typeof(self) weakSelf = self;
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
// Cancel button tappped.
[weakSelf dismissAlertController];
}];
UIAlertAction *removeAction = [UIAlertAction actionWithTitle:#"Remove" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
[weakSelf dismissAlertController];
//Do your actions
}];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self showAlertWithTitle:#"Are you sure you want to remove?" withMessage:nil withStyle:UIAlertControllerStyleActionSheet andActions:#[removeAction,cancelAction]];
}
else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
[self showAlertWithTitle:#"Are you sure you want to remove?" withMessage:nil withStyle:UIAlertControllerStyleActionSheet andActions:#[removeAction,cancelAction] andSource:sender];
}

How to show UIAlertController from Appdelegate

I'm working with PushNotification on iOS app. I would like to show a UIalertcontroller when the app receive a notification.
I try this code below in the AppDelegate:
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
But the UIAlertcontroller is showing in the root View (First screen) and for other uiviewcontroller i got warning or the app crashes.
try this
Objective-C
UIWindow* topWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
topWindow.rootViewController = [UIViewController new];
topWindow.windowLevel = UIWindowLevelAlert + 1;
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"APNS" message:#"received Notification" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(#"OK",#"confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.hidden = YES; // if you want to hide the topwindow then use this
topWindow = nil; // if you want to remove the topwindow then use this
}]];
[topWindow makeKeyAndVisible];
[topWindow.rootViewController presentViewController:alert animated:YES completion:nil];
Swift3 and above
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindow.Level.alert + 1
let alert = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow?.isHidden = true // if you want to hide the topwindow then use this
topWindow = nil // if you want to hide the topwindow then use this
})
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion: nil)
Detail description: http://www.thecave.com/2015/09/28/how-to-present-an-alert-view-using-uialertcontroller-when-you-dont-have-a-view-controller/
Shortest & Simplest :
Create a extension :
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)
}
return controller
} }
and then use it anywhere like
UIApplication.topViewController()?.present(UIViewController, animated: true, completion: nil)
With this you can present Alert or anything Anywhere
Example :
let alert = UIAlertController(title: "Your title", message: "Your message", preferredStyle: .alert)
let cancelButton = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(cancelButton)
UIApplication.topViewController()?.present(alert, animated: true, completion: nil)
ALTERNATE METHOD :
No need to create any Extension or any method or anything simply write the above 3 lines for creating an Alert and for presenting use :
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
That's it.! =)
Anbu.Karthik's answer but in
Swift 4.1
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindowLevelAlert + 1
let alert: UIAlertController = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: { (alertAction) in
topWindow?.isHidden = true
topWindow = nil
}))
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion:nil)
Thanks for reading this.
Swift 4.1
You can use the following code to present alert from AppDelegate
func showAlertFromAppDelegates(){
let alertVC = UIAlertController(title: "Oops" , message: "Presented Alert from AppDelegates", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.cancel) { (alert) in
exit(0) // Your code here
}
alertVC.addAction(okAction)
DispatchQueue.main.async {
var presentVC = self.window?.rootViewController
while let next = presentVC?.presentedViewController {
presentVC = next
}
presentVC?.present(alertVC, animated: true, completion: nil)
}
}
For the easiness, I used category
UIAlertController+UIWindow.h
#interface UIAlertController (UIWindow)
- (void)show;
- (void)show:(BOOL)animated;
#end
UIAlertController+UIWindow.m
#import <objc/runtime.h>
#interface UIAlertController (Private)
#property (nonatomic, strong) UIWindow *alertWindow;
#end
#implementation UIAlertController (Private)
#dynamic alertWindow;
- (void)setAlertWindow:(UIWindow *)alertWindow {
objc_setAssociatedObject(self, #selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIWindow *)alertWindow {
return objc_getAssociatedObject(self, #selector(alertWindow));
}
#end
#implementation UIAlertController (UIWindow)
- (void)show {
[self show:YES];
}
- (void)show:(BOOL)animated {
[self setupWindow];
[self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
}
- (void)setupWindow {
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
if ([delegate respondsToSelector:#selector(window)]) {
self.alertWindow.tintColor = delegate.window.tintColor;
}
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// precaution to insure window gets destroyed
self.alertWindow.hidden = YES;
self.alertWindow = nil;
}
Use:
UIAlertController *alertController;
// -- code --
[alertController show];
I have written a static class to make code reusable in swift 4, This class provied different methods for showing alerts.
class AlertUtility: NSObject {
static func showAlert(title: String!, message : String!, viewController: UIViewController) {
let alert = UIAlertController(title: title, message: message ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertAutoDismiss(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 0.8
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
topWindow.isHidden = true
}
}
// Show alert view with call back
static func showAlertWithCB(title: String, message: String, isConditional: Bool, viewController: UIViewController, completionBlock: #escaping (_: Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
// Check whether it's conditional or not ('YES' 'NO, or just 'OK')
if isConditional
{
alert.addAction(UIAlertAction(title: NSLocalizedString("yes", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("no", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(false)
}))
}
else
{
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
viewController.present(alert, animated: true, completion: nil)
}
static func showAlert(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 1
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: {(_ action: UIAlertAction) -> Void in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.isHidden = true
}))
}
static func showComingSoon(viewController: UIViewController) {
let alert = UIAlertController(title: "", message: "Coming Soon", preferredStyle: .alert)
viewController.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 1 seconds)
let when = DispatchTime.now() + 0.6
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
}
}
static func showGenericErrorMessageAlert(viewController: UIViewController) {
let alert = UIAlertController(title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("generic.error.message", comment: "") ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertWithTextField(viewController : UIViewController,completionBlock: #escaping (_: Bool, String) -> Void) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Report Event?", message: "", preferredStyle: .alert)
alert.view.tintColor = APP_ORANGE_COLOR
//2. Add the text field. You can configure it however you need.
//AlertUtility.addte
alert.addTextField { (textField) in
let heightConstraint = NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
textField.addConstraint(heightConstraint)
textField.placeholder = "Enter report reason here"
textField.tintColor = APP_ORANGE_COLOR
textField.autocapitalizationType = .sentences
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
// Force unwrapping because we know it exists.
completionBlock(true,"")
//print("Text field: \(textField.text)")
}))
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Submit", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
completionBlock(true,(textField?.text)!)
//print("Text field: \(textField.text)")
}))
// 4. Present the alert.
viewController.present(alert, animated: true, completion: nil)
let textField = alert.textFields![0]
let v = UIView.init(frame: textField.frame)
textField.addSubview(v)
v.frame = textField.frame
v.bounds = textField.bounds
v.backgroundColor = APP_ORANGE_COLOR
v.superview?.bringSubview(toFront: v)
}
}

How to show UIAlertController top of the presenting cotroller

I have the top view controller is presenting, and I want to show alert controller but it not display. Have any way to do it?
var appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
(Objective-C)
UIAlertController *alertVC = [UIAlertController
alertControllerWithTitle:#"myTitle" message:#"myMessage"
preferredStyle:UIAlertControllerStyleAlert];
[alertVC addAction:[UIAlertAction
actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action) {
[alertVC dismissViewControllerAnimated:YES completion:nil];
}
]];
[self presentViewController:alertVC animated:YES completion:nil];
Check this:
func showAlert() {
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
let yesAction = UIAlertAction(title: "YES", style: UIAlertActionStyle.Default) { (action: UIAlertAction!) -> Void in
print("YES tapped")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action: UIAlertAction!) -> Void in
print("Cancel tapped")
}
alert.addAction(yesAction)
alert.addAction(cancelAction)
var appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
Please also check and make sure that your rootViewController is not nil.
Finally I can solved my problem. It so easy, just input the controller we are standing on into the show alertcontroller function below:
func showAlerControler(title: String?, message: String, confirmButtonText: String?, cancelButtonText: String?, atController: UIViewController){
var alert: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
if let confirmStr = confirmButtonText{
alert.addAction(UIAlertAction(title: confirmStr, style: .Default, handler: { (ACTION) -> Void in
}))
}
if let cancelStr = cancelButtonText{
alert.addAction(UIAlertAction(title: cancelStr, style: .Default, handler: { (ACTION) -> Void in
}))
}
atController.presentViewController(alert, animated: true, completion: nil)
}
Don't use appDelegate.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
And you can standing on any controller to call showAlerControler and input atController is self

UIAlertController for large amount of text with scrolling functionality?

UIAlertController show small strings. when the size of string become larger. then some text from this alert is missing. is there any scrolling functionality available so that to scroll to the remaining text?
var alert = UIAlertController(title: "title here", message: "about 30 line text here", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
how to make an alert that show me text larger then 30 lines. i use swift.
It works without effort in the Playgrounds:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let window = UIWindow()
let viewController = UIViewController()
window.rootViewController = viewController
window.makeKeyAndVisible()
let message = (1...1000).reduce("") { $0 + "\($1)\n" }
let alert = UIAlertController(title: "title here", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "action here", style: .default, handler: nil))
viewController.present(alert, animated: true, completion: nil)
PlaygroundPage.current.liveView = window
I got 1000 scrollable lines:
It works fine for me in Objective C:
NSString* messageString = #"Enter your Long text here";
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Title"
message:messageString
preferredStyle:UIAlertControllerStyleAlert];
alertController.view.frame = [[UIScreen mainScreen] applicationFrame];
[alertController addAction:[UIAlertAction actionWithTitle:#“OK”
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action){
[self okButtonTapped];
}]];
[self presentViewController:alertController animated:YES completion:nil];
For Swift you can use this Code:
let alertController = UIAlertController(title: "Your Title", message: "Your Text", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
println(action)
}
alertController.addAction(cancelAction)
let destroyAction = UIAlertAction(title: "Destroy", style: .Destructive) { (action) in
println(action)
}
alertController.addAction(destroyAction)
self.presentViewController(alertController, animated: true) {
// ...
}

Resources