Does UIWindow function not work in Xcode11.3? - ios

I have alertcontroller code like this.
But I try to present alert, the alert don't show to me.
Have any idea to me.
Thanks.
public extension UIAlertController {
func show() {
let win = UIWindow(frame: UIScreen.main.bounds)
let vc = UIViewController()
vc.view.backgroundColor = .clear
win.rootViewController = vc
win.windowLevel = UIWindow.Level.alert + 1
win.makeKeyAndVisible()
vc.present(self, animated: true, completion: nil)
}
}
let alertController = UIAlertController(title: newTitle, message: newMessage, preferredStyle: .alert)
let submit = UIAlertAction(title: submitTitle, style: .default) { (action) in
clickOK()
}
alertController.addAction(submit)
if let cancelTitle = cancelTitle, !cancelTitle.isEmpty {
let cancel = UIAlertAction(title: cancelTitle, style: .cancel) { (action) in
if let clickCancel = clickCancel {
clickCancel()
}
}
alertController.addAction(cancel)
}
alertController.show()

Seems you need to hold UIWindow object until you want to show alert
Here is working code with little changes
private var win: UIWindow!
extension UIAlertController {
func show() {
win = UIWindow(frame: UIScreen.main.bounds)
let vc = UIViewController()
vc.view.backgroundColor = .clear
win.rootViewController = vc
win.windowLevel = .alert + 1
win.makeKeyAndVisible()
win.rootViewController?.present(self, animated: true, completion: nil)
}
open override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
win = nil
}
}
usage
Use in same way as you were previously using
let alertController = UIAlertController(title: newTitle, message: newMessage, preferredStyle: .alert)
let submit = UIAlertAction(title: submitTitle, style: .default) { (action) in
clickOK()
}
alertController.addAction(submit)
if let cancelTitle = cancelTitle, !cancelTitle.isEmpty {
let cancel = UIAlertAction(title: cancelTitle, style: .cancel) { (action) in
if let clickCancel = clickCancel {
clickCancel()
}
}
alertController.addAction(cancel)
}
alertController.show()

You can use this swift 5.0 extension also
public extension UIAlertController {
func showAlert() {
let window = UIWindow(frame: UIScreen.main.bounds)
let vc = UIViewController()
vc.view.backgroundColor = .clear
window.rootViewController = vc
window.windowLevel = UIWindow.Level.alert + 1
window.makeKeyAndVisible()
vc.present(self, animated: true, completion: nil)
}
}
Setup your alert controller with title and message and call like this
alertObject.showAlert()

Related

How to present UIAlertController in front of modal sheet in Swift

I'm trying to show an alert with a textfield from a modal in swift, but getting an error when I try to show it.
I have to use a UIAlertController because the default alert in Swift doesn't support Textfields currently.
I am calling my modal from my base view with
.sheet(isPresented: $showingLocationSheet) {
LocationSelectionView(selectedLocations: $locations)
}
From my LocationSelectionView, I then call the alert as follows:
let alert = UIAlertController(title: "Add Location", message: "Enter Location Name", preferredStyle: .alert)
alert.addTextField { (name) in
name.placeholder = "Bathroom"
}
let add = UIAlertAction(title: "Add", style: .default) { _ in
print("add Location")
}
let cancel = UIAlertAction(title: "Cancel", style: .destructive)
alert.addAction(add)
alert.addAction(cancel)
DispatchQueue.main.async {
UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true)
}
but then I receive this error:
Attempt to present <UIAlertController: 0x7fc8a78c7c00> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x7fc8a800b8d0> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x7fc8a800b8d0>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x7fc8a6e51980>.
I'm not quite sure how to get it to show here. I've also tried using an extension on the UIAlertController like this:
public extension UIAlertController {
func show() {
let win = UIWindow(frame: UIScreen.main.bounds)
let vc = UIViewController()
vc.view.backgroundColor = .clear
win.rootViewController = vc
win.windowLevel = UIWindow.Level.alert + 1 // Swift 3-4: UIWindowLevelAlert + 1
win.makeKeyAndVisible()
vc.present(self, animated: true, completion: nil)
}
as well as getting the top most controller like so:
func topmostController() -> UIViewController? {
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
}
return nil
}
but no luck. Any ideas?

UIAlertView shared class with return bool in Swift 4

protocol AlertDelegate: AnyObject {
func didGetResponse(text: String?)
}
class AlertClass{
weak var delegate: AlertDelegate?
static let sharedInstance = AlertClass()
//Show alert
func alertWindow(title: String, message: String) {
DispatchQueue.main.async(execute: {
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindow.Level.alert + 1
let alert2 = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction1 = UIAlertAction(title: "Yes", style: .destructive, handler: { action in
print("Yes")
})
let defaultAction2 = UIAlertAction(title: "No", style: .destructive, handler: { action in
print("No")
})
alert2.addAction(defaultAction1)
alert2.addAction(defaultAction2)
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alert2, animated: true, completion: nil)
})
}
}
How can I return bool value in this class?
class AlertClass{//This is shared class
weak var delegate: AlertDelegate?
static let sharedInstance = AlertClass()
//Show alert
func alertWindow(title: String, message: String, completion:#escaping (_ result: Bool) -> Void) {
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindow.Level.alert + 1
let alert2 = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction1 = UIAlertAction(title: "Yes", style: .destructive, handler: { action in
completion(true)
})
let defaultAction2 = UIAlertAction(title: "No", style: .destructive, handler: { action in
print("No")
completion(false)
})
alert2.addAction(defaultAction1)
alert2.addAction(defaultAction2)
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alert2, animated: true, completion: nil)
}
}
alert.alertWindow(title: "", message: "Checking Completion") { (result) in
if result{
print("It's yes")
}
else {
print("It's no")
}
}

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)
}
}

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)
}
}

Dismissing UIAlertController from UIWindow in UIWindow

I have a UIWindow that I'm using to display a second UIWindow whose rootViewController is presenting a UIAlertController. When I dismiss the UIAlertController, the main window is nonresponsive, and I'm not sure why. Here's my implementation:
func buttonPressed() {
var window = UIWindow(frame: UIScreen.mainScreen().bounds)
let alert = UIAlertController(title: "Add a comment to your post?", message: "You can also tag your friends.", preferredStyle: UIAlertControllerStyle.Alert)
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (action) -> Void in
// this isn't working
window.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
window.removeFromSuperview()
})
let ok = UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
// do something
})
alert.addAction(ok)
alert.addAction(cancel)
alert.addTextFieldWithConfigurationHandler({(txtField: UITextField) in
txtField.placeholder = "What's on your mind?"
txtField.keyboardType = UIKeyboardType.Default
txtField.autocapitalizationType = .None
})
window.rootViewController = UIViewController()
window.backgroundColor = UIColor.clearColor()
window.makeKeyAndVisible()
window.rootViewController?.presentViewController(alert, animated: true, completion: nil)
self.addSubview(window)
self.repostButton.setTitle("Pressed!", forState: UIControlState.Normal)
}
Got it. Just called window.hidden = truein the completion handler of cancel. Guess I just overthought it. :)

Resources