-1

My app's application(_:didFinishLaunchingWithOptions:launchOptions:) is creating an overlay like this:

window.makeKeyAndVisible()
let launchStoryboard = UIStoryboard(name: "LaunchScreen", bundle: nil)
let overlayView = launchStoryboard.instantiateInitialViewController()!.view!
window.addSubview(overlayView)

The app's initial view controller as defined in Main.storyboard is a UITabBarController whose 1st tab contains a UINavigationController. viewDidLoad() of its root view controller calls EKEventStore.authorizationStatus(for:).

At this point the app seemingly stalls and only the overlay is visible. When I stop the app the dialog box that asks whether the app should be allowed to access the calendar appears. It was apparently hidden below the overlay.

How can I ensure that the dialog box appears at the very front of the screen so the user gets a chance to answer its actual question?

UPDATE Here is more information about the general context in response to questions: The reason for the code in the app's delegate is that -- unless it has occurred on a previous launch -- I need to prompt the user for server credentials, obtain data from the server and store some of this data in EKEvents. The overlay supports presenting the view controller for obtaining the user’s credentials (see here). The overlay will be removed when data has been received from the server. The call to makeKeyAndVisible is necessary in order for UIApplication.shared.keyWindow to receive a value despite the early stage in the app’s life cycle. That value is required for presenting the said view controller for obtaining credentials.

Community
  • 1
  • 1
Drux
  • 11,992
  • 13
  • 66
  • 116
  • Are you sure you have this tab view controller in the LaunchScreen storyboard? It usually contains just the launch screen (as the name suggests) and the rest would be in a Main storyboard... Also did you try to set a breakpoint in your view controller to see if it even gets there? – kender Oct 05 '16 at 12:35
  • @kender No, the tab view controller is not in LaunchScreen storyboard, but in Main.storyboard (see edit). – Drux Oct 05 '16 at 18:44
  • what's the reason for the code in your AppDelegate then? Do you remove the overlay at any point? And what if you don't makeKeyAndVisible the overlay window? – kender Oct 05 '16 at 18:50
  • @kender I've updated the Q to answer the questions you have raised. (All of this has worked until reason, so the general approach is perhaps reasonable.) – Drux Oct 09 '16 at 06:34

1 Answers1

0

The problem was not that the dialog box was hidden behind the overlay but that I called EKEventStore's requestAccess(to:completion:) synchronously (by waiting after the call for a semaphore that was signaled inside the completion handler) inside application(_:didFinishLaunchingWithOptions:launchOptions:). Hence the entire app stalled and the dialog box was not even displayed.

The solution consisted in requesting access asynchronously. The following scheme is currently good enough:

  • instance variable calendarEvent is nil if access to an EKCalendar was not (yet) granted
  • requestAccess(to:completion:) is called from inside application(_:didFinishLaunchingWithOptions:launchOptions:)
  • calendarEvent is set to this EKCalendar in completion handler of requestAccess(to:completion:)
  • before reading or writing to calendar app checks if calendarEvent != nil
  • during cycle of run loop with call to application(_:didFinishLaunchingWithOptions:launchOptions:) calendarEvent remains nil; app behaves as if calendar were empty
  • during later cycles of run loop calendarEvent has been set; app actually writes to calendar only during those later cycles
Drux
  • 11,992
  • 13
  • 66
  • 116