UIAlertController in iOS 8.x cannot response touch event, is the touch event sent to the key window object?

479 Views Asked by At

I have a problem abount UIAlertController. It cannot receive any touch events and be dismissed. I persent the alert in this way:

UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController
[controller presentViewController:alertController animated:YES completion:nil];

After this time, the alert view was presented.But when I try to click ‘OK’, there’s no response. So I click the blank area around the alert view, the button on the lower layer receive it and make a response.

In my application, there’s a third-party SDK which provides a suspension button and login/logout UI. The button will always be there, but UI wouldn’t be presented except I call it. The SDK will add two windows into the application’s window array when it was initialized. So there’re three objects in ‘[UIApplication sharedApplication].windows’. Look like this:

[0]:”<TS_PlatformWindow: 0x16e15ac0; baseClass = UIWindow; frame = (0 0; 568 320); gestureRecognizers = <NSArray: 0x186a85b0>; layer = <UIWindowLayer: 0x186a8a20>>",
[1]:”<UIWindow: 0x16e1a060; frame = (0 0; 568 320); autoresize = W+H; tag = 10000000; gestureRecognizers = <NSArray: 0x16e19af0>; layer = <UIWindowLayer: 0x16e19f40>>",
[2]:“<UITextEffectsWindow: 0x16f576c0; frame = (0 0; 568 320); opaque = NO; gestureRecognizers = <NSArray: 0x16f57120>; layer = <UIWindowLayer: 0x16f574b0>>"

The window of my application at index 1, windows at index 0 and 2 are third-party SDK’s.

As the official document in iOS Developer Library, here is the quote: ‘An event travels along a specific path until it is delivered to an object that can handle it. First, the singleton UIApplication object takes an event from the top of the queue and dispatches it for handling. Typically, it sends the event to the app’s key window object, which passes the event to an initial object for handling. The initial object depends on the type of event.’ from https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/event_delivery_responder_chain/event_delivery_responder_chain.html

As my understanding, touch events should be sent to the key window of the app, but actually the window of my application isn’t. The document use the word ’Typically’, so I’m not sure if the situation in my App is an exception. There’s no mention about how the event delivered if there’re multiply windows exist.

So I change my code like this:

UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController
for (UIWindow *win in wins.reverseObjectEnumerator) {
      UIViewController *rootController = win.rootViewController;
      if (rootController != nil) {
           controller = rootController;
           break;
     }
}
[controller presentViewController:alertController animated:YES completion:nil];

The default value of ‘controller’ will be assigned to ‘keyWindow.rootViewController’ Travel the window array of the application in reverse order, and select the top-most object’s ‘rootViewController’ to present the alert. It works!

This problem confuse me if this is the correct solution? Or there is another document could give an explanation?

PS:

Every operations are on the main thread

1

There are 1 best solutions below

0
On

I cannot access to background view from UIAlertController, therefore using addGestureRecognizer for current keyWindow -

class MyAlertController: UIAlertController, UIGestureRecognizerDelegate {

var tapGesture : UITapGestureRecognizer?

override func viewDidAppear(animated: Bool)
{
    tapGesture = UITapGestureRecognizer(target: self, action:Selector("tapGesture:"))
    tapGesture!.delegate = self
    UIApplication.sharedApplication().keyWindow?.addGestureRecognizer(tapGesture!)
}

func tapGesture(sender: UITapGestureRecognizer? = nil)
{
    UIApplication.sharedApplication().keyWindow?.removeGestureRecognizer(tapGesture!)
    self.dismissViewControllerAnimated(true, completion: nil)
}
}