Working with Xcode 10.1 and Swift 4.2
I have a complex app that uses a UINavigationController
implemented in the AppDelegate
.
The rootViewController of the navigationController is a DashboardController()
class (subclass of UIViewController
)
The DashboardController
implements a left menu drawer using several ViewControllers (with self.addChild(viewController)
)
Everything works fine, except when I need to push a viewController to present a BarCodeScannerView().
The barebone barCodeScannerView can be pushed and popped as expected.
The problems arises when I request access to the camera (only the first time).
As soon as I present the
Device.requestAccess(for:)
as follow: the viewController is popped and the previous view (rootViewController) is presented. (Still with the "App would like to access the camera" AlertView)func requestCameraAccess() { AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in if granted { self.launchScanner() } else { self.goBack() } } }
If I click "OK" The system will register that the access was granted, but the
applicationDidBecomeActive
(in theAppDelegate
) is called after aprox 1 second. I have some initializers inapplicationDidBecomeActive
, and they all are executed again. And after a quick delay, everything works fine.
BTW: applicationWillResignActive
, applicationDidEnterBackground
and applicationWillEnterForeground
are NOT called. So it is clear that this is not part of an App LifeCycle.
Any idea what might me going on here? What can make the system call applicationDidBecomeActive
within the app? and still keep everything running?
Thx in advance...
UPDATE After reading the comments, I was able to isolate the issue #2 as follows:
A simple/barebones project with a UINavigationController
with a dashboardViewController as rootViewController
. The dashboardViewController pushes a CameraViewController()
in viewDidLoad()
. The cameraViewController requests access to the camera. When clicking OK, the call to applicationDidBecomeActive
is triggered.
The full project is attached. (except the "Privacy - Camera Usage Description" key in the .plist.
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? = UIWindow()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let dashboardViewController = DashboardViewController()
window?.rootViewController = UINavigationController(rootViewController: dashboardViewController)
window?.makeKeyAndVisible()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("applicationDidBecomeActive")
}
func applicationWillResignActive(_ application: UIApplication) {}
func applicationDidEnterBackground(_ application: UIApplication) {}
func applicationWillEnterForeground(_ application: UIApplication) {}
func applicationWillTerminate(_ application: UIApplication) {}
}
class DashboardViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
let cameraVC = CameraViewController()
self.navigationController?.pushViewController(cameraVC, animated: true)
}
}
import AVFoundation
class CameraViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in
if granted {
print("Access granted")
}
}
}
}
I'd say the problem is just with your testing procedure. When I run your code with a
print
statement inapplicationWillResignActive
, this is what I see:That seems completely in order and normal. It would have been weird to get a spurious
didBecomeActive
, but that is not what's happening; we resign active and then become active again, which is fine. You should expect that at any time your app can resign active and become active again. Many things in the normal lifecycle can cause that, and the presentation of an out-of-process dialog like the authorization dialog can reasonably be one of them. You should write your code in such a way as to cope with that possibility.