ios - दृश्य नियंत्रक में नहीं होने पर UIAlertController को कैसे पेश करें?




(20)

@ agilityvision का उत्तर स्विफ्ट 4 / आईओएस 11 में अनुवाद किया गया। मैंने स्थानीय तारों का उपयोग नहीं किया है, लेकिन आप इसे आसानी से बदल सकते हैं:

import UIKit

/** An alert controller that can be called without a view controller.
 Creates a blank view controller and presents itself over that
 **/
class AlertPlusViewController: UIAlertController {

    private var alertWindow: UIWindow?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        self.alertWindow?.isHidden = true
        alertWindow = nil
    }

    func show() {
        self.showAnimated(animated: true)
    }

    func showAnimated(animated _: Bool) {

        let blankViewController = UIViewController()
        blankViewController.view.backgroundColor = UIColor.clear

        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = blankViewController
        window.backgroundColor = UIColor.clear
        window.windowLevel = UIWindowLevelAlert + 1
        window.makeKeyAndVisible()
        self.alertWindow = window

        blankViewController.present(self, animated: true, completion: nil)
    }

    func presentOkayAlertWithTitle(title: String?, message: String?) {

        let alertController = AlertPlusViewController(title: title, message: message, preferredStyle: .alert)
        let okayAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
        alertController.addAction(okayAction)
        alertController.show()
    }

    func presentOkayAlertWithError(error: NSError?) {
        let title = "Error"
        let message = error?.localizedDescription
        presentOkayAlertWithTitle(title: title, message: message)
    }
}

परिदृश्य: उपयोगकर्ता दृश्य नियंत्रक पर एक बटन पर टैप करता है। नेविगेशन स्टैक में व्यू कंट्रोलर सबसे ऊपर (स्पष्ट रूप से) है। टैप एक यूटिलिटी क्लास विधि को दूसरी कक्षा में बुलाता है। एक बुरी चीज होती है और मैं दृश्य नियंत्रक पर नियंत्रण रिटर्न से पहले वहां एक चेतावनी प्रदर्शित करना चाहता हूं।

+ (void)myUtilityMethod {
    // do stuff
    // something bad happened, display an alert.
}

यह UIAlertView साथ संभव था (लेकिन शायद काफी उचित नहीं)।

इस मामले में, आप UIAlertController में वहां UIAlertController कैसे प्रस्तुत करते हैं?


Aviel सकल उत्तर में एक्सटेंशन बनाएँ। यहां आपके पास उद्देश्य-सी एक्सटेंशन है।

यहां आपके पास हेडर फ़ाइल * है

//  UIAlertController+Showable.h

#import <UIKit/UIKit.h>

@interface UIAlertController (Showable)

- (void)show;

- (void)presentAnimated:(BOOL)animated
             completion:(void (^)(void))completion;

- (void)presentFromController:(UIViewController *)viewController
                     animated:(BOOL)animated
                   completion:(void (^)(void))completion;

@end

और कार्यान्वयन: * एमएम

//  UIAlertController+Showable.m

#import "UIAlertController+Showable.h"

@implementation UIAlertController (Showable)

- (void)show
{
    [self presentAnimated:YES completion:nil];
}

- (void)presentAnimated:(BOOL)animated
             completion:(void (^)(void))completion
{
    UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
    if (rootVC != nil) {
        [self presentFromController:rootVC animated:animated completion:completion];
    }
}

- (void)presentFromController:(UIViewController *)viewController
                     animated:(BOOL)animated
                   completion:(void (^)(void))completion
{

    if ([viewController isKindOfClass:[UINavigationController class]]) {
        UIViewController *visibleVC = ((UINavigationController *)viewController).visibleViewController;
        [self presentFromController:visibleVC animated:animated completion:completion];
    } else if ([viewController isKindOfClass:[UITabBarController class]]) {
        UIViewController *selectedVC = ((UITabBarController *)viewController).selectedViewController;
        [self presentFromController:selectedVC animated:animated completion:completion];
    } else {
        [viewController presentViewController:self animated:animated completion:completion];
    }
}

@end

आप इस कार्यान्वयन फ़ाइल में इस एक्सटेंशन का उपयोग इस तरह कर रहे हैं:

#import "UIAlertController+Showable.h"

UIAlertController* alert = [UIAlertController
    alertControllerWithTitle:@"Title here"
                     message:@"Detail message here"
              preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction* defaultAction = [UIAlertAction
    actionWithTitle:@"OK"
              style:UIAlertActionStyleDefault
            handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];

// Add more actions if needed

[alert show];

आप स्विफ्ट 2.2 के साथ निम्नलिखित कर सकते हैं:

let alertController: UIAlertController = ...
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

और स्विफ्ट 3.0:

let alertController: UIAlertController = ...
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)

उद्देश्य-सी में चेतावनी प्रस्तुत करने के लिए शॉर्टेंड तरीका:

[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:alertController animated:YES completion:nil];

जहां alertController आपका UIAlertController ऑब्जेक्ट है।

नोट: आपको यह सुनिश्चित करने की भी आवश्यकता होगी कि आपकी सहायक कक्षा UIViewController बढ़ाती है


जेवी के उत्तर में जोड़ना (और ऑब्जेक्टिव-सी पर वापस स्विच करना), आप ऐसी परिस्थिति में भाग सकते हैं जहां आपका रूट व्यू कंट्रोलर कुछ अन्य वीसी को एक सेग्यू या कुछ और के माध्यम से पेश कर रहा है। रूट वीसी पर प्रस्तुत क्यू कंट्रोलर कॉलिंग इस पर ध्यान रखेगी:

[[UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController presentViewController:alertController animated:YES completion:^{}];

इसने एक मुद्दा हल किया जहां मेरे पास रूट वीसी एक और वीसी से गुजर गया था, और अलर्ट कंट्रोलर पेश करने की बजाय, उपरोक्त रिपोर्ट की गई चेतावनी जारी की गई थी:

Warning: Attempt to present <UIAlertController: 0x145bfa30> on <UINavigationController: 0x1458e450> whose view is not in the window hierarchy!

मैंने इसका परीक्षण नहीं किया है, लेकिन यह भी जरूरी हो सकता है यदि आपका रूट वीसी एक नेविगेशन नियंत्रक होता है।


डब्ल्यूडब्ल्यूडीसी में, मैंने प्रयोगशालाओं में से एक में रुक दिया और एक ऐप्पल अभियंता से यही सवाल पूछा: " UIAlertController प्रदर्शित करने के लिए सबसे अच्छा अभ्यास क्या था?" और उन्होंने कहा कि उन्हें यह सवाल बहुत मिल रहा है और हमने मजाक किया कि उन्हें इस पर एक सत्र होना चाहिए था। उन्होंने कहा कि आंतरिक रूप से ऐप्पल एक पारदर्शी UIViewController साथ UIWindow बना रहा है और उसके बाद UIAlertController प्रस्तुत कर रहा है। मूल रूप से डायलन बेट्टरमैन के जवाब में क्या है।

लेकिन मैं UIAlertController उप-वर्ग का उपयोग नहीं करना चाहता था क्योंकि मुझे अपने पूरे ऐप में अपना कोड बदलने की आवश्यकता होगी। तो किसी संबंधित ऑब्जेक्ट की मदद से, मैंने UIAlertController पर एक श्रेणी बनाई जो उद्देश्य-सी में एक show विधि प्रदान करता है।

यहां प्रासंगिक कोड है:

#import "UIAlertController+Window.h"
#import <objc/runtime.h>

@interface UIAlertController (Window)

- (void)show;
- (void)show:(BOOL)animated;

@end

@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 (Window)

- (void)show {
    [self show:YES];
}

- (void)show:(BOOL)animated {
    self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.alertWindow.rootViewController = [[UIViewController alloc] init];

    id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
    // Applications that does not load with UIMainStoryboardFile might not have a window property:
    if ([delegate respondsToSelector:@selector(window)]) {
        // we inherit the main window's tintColor
        self.alertWindow.tintColor = delegate.window.tintColor;
    }

    // window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
    UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
    self.alertWindow.windowLevel = topWindow.windowLevel + 1;

    [self.alertWindow makeKeyAndVisible];
    [self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    // precaution to insure window gets destroyed
    self.alertWindow.hidden = YES;
    self.alertWindow = nil;
}

@end

नमूना उपयोग यहां दिया गया है:

// need local variable for TextField to prevent retain cycle of Alert otherwise UIWindow
// would not disappear after the Alert was dismissed
__block UITextField *localTextField;
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Global Alert" message:@"Enter some text" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    NSLog(@"do something with text:%@", localTextField.text);
// do NOT use alert.textfields or otherwise reference the alert in the block. Will cause retain cycle
}]];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
    localTextField = textField;
}];
[alert show];

UIAlertController को हटाए जाने पर बनाए गए UIWindow नष्ट कर दिया जाएगा, क्योंकि यह एकमात्र ऑब्जेक्ट है जो UIWindow को बनाए रखता है। लेकिन अगर आप किसी संपत्ति में UIAlertController को असाइन करते हैं या एक्शन ब्लॉक में से किसी एक में अलर्ट तक पहुंचने के लिए इसकी गणना को बनाए रखने का कारण बनता है, तो UIWindow स्क्रीन पर रहेगा, आपके यूआई को लॉक कर देगा। UITextField तक पहुंचने की आवश्यकता के मामले में से बचने के लिए उपरोक्त नमूना उपयोग कोड देखें।

मैंने एक परीक्षण परियोजना के साथ FFGlobalAlertController रेपो बनाया: FFGlobalAlertController


निम्नलिखित समाधान काम नहीं किया, भले ही यह सभी संस्करणों के साथ काफी आशाजनक लग रहा था। यह समाधान चेतावनी पैदा कर रहा है ।

चेतावनी: उपस्थिति का प्रयास खिड़की पदानुक्रम में नहीं है!

https://.com/a/34487871/2369867 => यह तब आशाजनक लग रहा है। लेकिन यह Swift 3 में नहीं था। तो मैं स्विफ्ट 3 में इसका जवाब दे रहा हूं और यह टेम्पलेट उदाहरण नहीं है

एक बार जब आप किसी भी फ़ंक्शन के अंदर पेस्ट करते हैं तो यह पूरी तरह से कार्यात्मक कोड होता है।

त्वरित Swift 3 स्वयं निहित कोड

let alertController = UIAlertController(title: "<your title>", message: "<your message>", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.cancel, handler: nil))

let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)

स्विफ्ट 3 में यह परीक्षण और कामकाजी कोड है।


मेरे answer क्रॉस पोस्ट करें क्योंकि इन दो धागे को डुप्स के रूप में फ़्लैग नहीं किया गया है ...

अब जब UIViewController उत्तरदाता श्रृंखला का हिस्सा है, तो आप ऐसा कुछ कर सकते हैं:

if let vc = self.nextResponder()?.targetForAction(#selector(UIViewController.presentViewController(_:animated:completion:)), withSender: self) as? UIViewController {

    let alert = UIAlertController(title: "A snappy title", message: "Something bad happened", preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))

    vc.presentViewController(alert, animated: true, completion: nil)
}

यह सामान्य दृश्य नियंत्रकों के लिए स्विफ्ट में काम करता है और यहां तक ​​कि यदि स्क्रीन पर नेविगेशन नियंत्रक है:

let alert = UIAlertController(...)

let alertWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.presentViewController(alert, animated: true, completion: nil)

स्विफ्ट 4 में विस्तार, परीक्षण और काम करने के रूप में मिथिकलकोडर का जवाब यहां दिया गया है:

extension UIAlertController {

    func presentInOwnWindow(animated: Bool, completion: (() -> Void)?) {
        let alertWindow = UIWindow(frame: UIScreen.main.bounds)
        alertWindow.rootViewController = UIViewController()
        alertWindow.windowLevel = UIWindowLevelAlert + 1;
        alertWindow.makeKeyAndVisible()
        alertWindow.rootViewController?.present(self, animated: animated, completion: completion)
    }

}

उदाहरण का उपयोग:

let alertController = UIAlertController(title: "<Alert Title>", message: "<Alert Message>", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Close", style: .cancel, handler: nil))
alertController.presentInOwnWindow(animated: true, completion: {
    print("completed")
})

In Swift 3

let alertLogin = UIAlertController.init(title: "Your Title", message:"Your message", preferredStyle: .alert)
                                    alertLogin.addAction(UIAlertAction(title: "Done", style:.default, handler: { (AlertAction) in

                                    }))
                                    self.window?.rootViewController?.present(alertLogin, animated: true, completion: nil)

Swift 4+

Solution I use for years with no issues at all. First of all I extend UIWindow to find it's visibleViewController. NOTE : if you using custom collection* classes (such as side menu) you should add handler for this case in following extension. After getting top most view controller it's easy to present UIAlertController just like UIAlertView .

extension UIAlertController {

  func show(animated: Bool = true, completion: (() -> Void)? = nil) {
    if let visibleViewController = UIApplication.shared.keyWindow?.visibleViewController {
      visibleViewController.present(self, animated: animated, completion: completion)
    }
  }

}

extension UIWindow {

  var visibleViewController: UIViewController? {
    guard let rootViewController = rootViewController else {
      return nil
    }
    return visibleViewController(for: rootViewController)
  }

  private func visibleViewController(for controller: UIViewController) -> UIViewController {
    var nextOnStackViewController: UIViewController? = nil
    if let presented = controller.presentedViewController {
      nextOnStackViewController = presented
    } else if let navigationController = controller as? UINavigationController,
      let visible = navigationController.visibleViewController {
      nextOnStackViewController = visible
    } else if let tabBarController = controller as? UITabBarController,
      let visible = (tabBarController.selectedViewController ??
        tabBarController.presentedViewController) {
      nextOnStackViewController = visible
    }

    if let nextOnStackViewController = nextOnStackViewController {
      return visibleViewController(for: nextOnStackViewController)
    } else {
      return controller
    }
  }

}

@agilityvision's answer is so good. I have sense used in swift projects so I thought I would share my take on his answer using swift 3.0

fileprivate class MyUIAlertController: UIAlertController {

  typealias Handler = () -> Void

  struct AssociatedKeys {
    static var alertWindowKey = "alertWindowKey"
  }

  dynamic var _alertWindow: UIWindow?

  var alertWindow: UIWindow? {
    return objc_getAssociatedObject(self, &AssociatedKeys.alertWindowKey) as? UIWindow
  }


  func setAlert(inWindow window: UIWindow) {
    objc_setAssociatedObject(self, &AssociatedKeys.alertWindowKey, _alertWindow, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  }

  func show(completion: Handler? = nil) {
    show(animated: true, completion: completion)
  }

  func show(animated: Bool, completion: Handler? =  nil) {
    _alertWindow = UIWindow(frame: UIScreen.main.bounds)
    _alertWindow?.rootViewController = UIViewController()

    if let delegate: UIApplicationDelegate = UIApplication.shared.delegate, let window = delegate.window {
      _alertWindow?.tintColor = window?.tintColor

    }

    let topWindow = UIApplication.shared.windows.last
    _alertWindow?.windowLevel = topWindow?.windowLevel ?? 0 + 1
    _alertWindow?.makeKeyAndVisible()
    _alertWindow?.rootViewController?.present(self, animated: animated, completion: completion)
  }

  fileprivate override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    _alertWindow?.isHidden = true
    _alertWindow = nil
  }
}

Agilityvision के उत्तर में सुधार, आपको एक पारदर्शी रूट व्यू कंट्रोलर के साथ एक विंडो बनाने और वहां से अलर्ट व्यू पेश करने की आवश्यकता होगी।

हालांकि जब तक आपके अलर्ट कंट्रोलर में कोई कार्रवाई हो, तब तक आपको विंडो का संदर्भ रखने की आवश्यकता नहीं है । एक्शन हैंडलर ब्लॉक के अंतिम चरण के रूप में, आपको क्लीनअप कार्य के हिस्से के रूप में विंडो को छिपाने की आवश्यकता है। हैंडलर ब्लॉक में विंडो का संदर्भ रखते हुए, यह एक अस्थायी परिपत्र संदर्भ बनाता है जो चेतावनी नियंत्रक को खारिज कर दिया जाता है।

UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = [UIViewController new];
window.windowLevel = UIWindowLevelAlert + 1;

UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:... message:... preferredStyle:UIAlertControllerStyleAlert];

[alertCtrl addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK",@"Generic confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    ... // do your stuff

    // very important to hide the window afterwards.
    // this also keeps a reference to the window until the action is invoked.
    window.hidden = YES;
}]];

[window makeKeyAndVisible];
[window.rootViewController presentViewController:alertCtrl animated:YES completion:nil];

I use this code with some little personal variations in my AppDelegate class

-(UIViewController*)presentingRootViewController
{
    UIViewController *vc = self.window.rootViewController;
    if ([vc isKindOfClass:[UINavigationController class]] ||
        [vc isKindOfClass:[UITabBarController class]])
    {
        // filter nav controller
        vc = [AppDelegate findChildThatIsNotNavController:vc];
        // filter tab controller
        if ([vc isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tbc = ((UITabBarController*)vc);
            if ([tbc viewControllers].count > 0) {
                vc = [tbc viewControllers][tbc.selectedIndex];
                // filter nav controller again
                vc = [AppDelegate findChildThatIsNotNavController:vc];
            }
        }
    }
    return vc;
}
/**
 *   Private helper
 */
+(UIViewController*)findChildThatIsNotNavController:(UIViewController*)vc
{
    if ([vc isKindOfClass:[UINavigationController class]]) {
        if (((UINavigationController *)vc).viewControllers.count > 0) {
            vc = [((UINavigationController *)vc).viewControllers objectAtIndex:0];
        }
    }
    return vc;
}

If anyone is interested I created a Swift 3 version of @agilityvision answer. The code:

import Foundation
import UIKit

extension UIAlertController {

    var window: UIWindow? {
        get {
            return objc_getAssociatedObject(self, "window") as? UIWindow
        }
        set {
            objc_setAssociatedObject(self, "window", newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    open override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        self.window?.isHidden = true
        self.window = nil
    }

    func show(animated: Bool = true) {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = UIViewController(nibName: nil, bundle: nil)

        let delegate = UIApplication.shared.delegate
        if delegate?.window != nil {
            window.tintColor = delegate!.window!!.tintColor
        }

        window.windowLevel = UIApplication.shared.windows.last!.windowLevel + 1

        window.makeKeyAndVisible()
        window.rootViewController!.present(self, animated: animated, completion: nil)

        self.window = window
    }
}

Seems to work:

static UIViewController *viewControllerForView(UIView *view) {
    UIResponder *responder = view;
    do {
        responder = [responder nextResponder];
    }
    while (responder && ![responder isKindOfClass:[UIViewController class]]);
    return (UIViewController *)responder;
}

-(void)showActionSheet {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
    [alertController addAction:[UIAlertAction actionWithTitle:@"Do it" style:UIAlertActionStyleDefault handler:nil]];
    [viewControllerForView(self) presentViewController:alertController animated:YES completion:nil];
}

There 2 approaches that you can use:

-Use UIAlertView or 'UIActionSheet' instead (not recommended, cause it deprecated in iOS 8 but it works now)

-Somehow remember the last view controller which is presented. Here is example.

@interface UIViewController (TopController)
+ (UIViewController *)topViewController;
@end

// implementation

#import "UIViewController+TopController.h"
#import <objc/runtime.h>

static __weak UIViewController *_topViewController = nil;

@implementation UIViewController (TopController)

+ (UIViewController *)topViewController {
    UIViewController *vc = _topViewController;
    while (vc.parentViewController) {
        vc = vc.parentViewController;
    }
    return vc;
}

+ (void)load {
    [super load];
    [self swizzleSelector:@selector(viewDidAppear:) withSelector:@selector(myViewDidAppear:)];
    [self swizzleSelector:@selector(viewWillDisappear:) withSelector:@selector(myViewWillDisappear:)];
}

- (void)myViewDidAppear:(BOOL)animated {
    if (_topViewController == nil) {
        _topViewController = self;
    }

    [self myViewDidAppear:animated];
}

- (void)myViewWillDisappear:(BOOL)animated {
    if (_topViewController == self) {
        _topViewController = nil;
    }

    [self myViewWillDisappear:animated];
}

+ (void)swizzleSelector:(SEL)sel1 withSelector:(SEL)sel2
{
    Class class = [self class];

    Method originalMethod = class_getInstanceMethod(class, sel1);
    Method swizzledMethod = class_getInstanceMethod(class, sel2);

    BOOL didAddMethod = class_addMethod(class,
                                        sel1,
                                        method_getImplementation(swizzledMethod),
                                        method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
                            sel2,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

@end 

उपयोग:

[[UIViewController topViewController] presentViewController:alertController ...];

create helper class AlertWindow and than use as

let alertWindow = AlertWindow();
let alert = UIAlertController(title: "Hello", message: "message", preferredStyle: .alert);
let cancel = UIAlertAction(title: "Ok", style: .cancel){(action) in

    //....  action code here

    // reference to alertWindow retain it. Every action must have this at end

    alertWindow.isHidden = true;

   //  here AlertWindow.deinit{  }

}
alert.addAction(cancel);
alertWindow.present(alert, animated: true, completion: nil)


class AlertWindow:UIWindow{

    convenience init(){
        self.init(frame:UIScreen.main.bounds);
    }

    override init(frame: CGRect) {
        super.init(frame: frame);
        if let color = UIApplication.shared.delegate?.window??.tintColor {
            tintColor = color;
        }
        rootViewController = UIViewController()
        windowLevel = UIWindowLevelAlert + 1;
        makeKeyAndVisible()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit{
        //  semaphor.signal();
    }

    func present(_ ctrl:UIViewController, animated:Bool, completion: (()->Void)?){
        rootViewController!.present(ctrl, animated: animated, completion: completion);
    }
}

मेरे पास एक ही समस्या थी, नेविगेशन नियंत्रक द्वारा प्रस्तुत UITableViewController में बैठे हुए एक अलर्ट प्रस्तुत करने का प्रयास किया। यहां जवाब और कुछ परीक्षणों के माध्यम से पढ़ने के बाद, निम्नलिखित कोड एक्सटेंशन आदि की आवश्यकता के बिना ठीक और विश्वसनीय काम किया।

self.navigationController?.present(alertController, animated: true, completion: nil)

शायद वह किसी की मदद करें ...

.. खुश कोडिंग







uialertcontroller