在应用启动之前执行完成处理程序 [英] Performing a completion handler before app launches

查看:87
本文介绍了在应用启动之前执行完成处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过以下两种方式之一打开应用程序:

I am attempting to open an app in one of two ways:

  1. 如果用户没有保存UserDefaults,则打开WelcomeViewController
  2. 如果用户已保存UserDefaults,则打开MenuContainerViewController作为主页
  1. If the user has no UserDefaults saved, then open up a WelcomeViewController
  2. If the user has UserDefaults saved, then open up a MenuContainerViewController as a home page

在第2步中,如果保存了UserDefaults,那么我需要使用Firebase登录用户,该用户通过具有完成处理程序的函数拥有.如果是第2步,我想在完成块内打开MenuContainerViewController,而不会出现任何UI打ic.

In step 2, if there are UserDefaults saved, then I need to log a user in using Firebase which I have through a function with a completion handler. If step 2 is the case, I want to open MenuContainerViewController within the completion block without any UI hiccups.

这是我当前拥有的代码:

Here is the code I have currently:

func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    self.window = UIWindow(frame: UIScreen.main.bounds)

    FirebaseApp.configure()

    guard
        let email = UserDefaults.standard.string(forKey: "email"),
        let password = UserDefaults.standard.string(forKey: "password")
    else {
        // User has no defaults, open welcome screen
        let welcomeViewController = WelcomeViewController()
        self.window?.rootViewController = welcomeViewController
        self.window?.makeKeyAndVisible()
        return true
    }

    // User has defaults saved locally, open home screen of app
    let authentificator = Authentificator()
    authentificator.login(with: email, password) { result, _ in
        if result {
            let menuContainerViewController = MenuContainerViewController()
            self.window?.rootViewController = menuContainerViewController
            self.window?.makeKeyAndVisible()
        }
    }

    return true
}

这是当前用户界面的视频,当我需要运行完成处理程序时,过渡到应用程序的过程并不顺利(有一秒钟短暂的黑屏).

Here is a video of the current UI, when I need to run the completion handler, the transition is not smooth into the app (there is a brief second with a black screen).

请帮助我弄清楚如何使应用程序顺利启动.

Please help me figure out how to make a smooth app launch.

推荐答案

在Firebase应用程序中,我不得不同样地处理各种情况.我通常要做的是制作InitialViewController.无论如何,这都是始终加载的视图控制器.最初,此视图控制器已设置为与启动屏幕完全一样无缝显示.

I've had to handle situations similarly in my Firebase applications. What I typically do is make an InitialViewController. This is the view controller that is always loaded, no matter what. This view controller is initially set up to seamlessly look exactly like the launch screen.

这是InitialViewController在界面生成器中的外观:

This is what the InitialViewController looks like in the interface builder:

这是我的启动屏幕:

And this is what my launch screen looks like:

因此,当我说它们看起来完全相同时,是指它们看起来完全相同.此InitialViewController的唯一目的是处理异步检查并决定下一步要做什么,所有这些看起来都像启动屏幕一样.您甚至可以在两个视图控制器之间复制/粘贴界面构建器元素.

So when I say they look exactly the same, I mean they look exactly the same. The sole purpose of this InitialViewController is to handle this asynchronous check and decide what to do next, all while looking like the launch screen. You may even copy/paste interface builder elements between the two view controllers.

因此,在此InitialViewController中,您可以在viewDidAppear()中进行身份验证检查.如果用户已登录,我们将对主视图控制器执行segue.如果没有,我们会为用户的入职元素设置动画.展示我的意思的gif相当大(在尺寸方面和在数据方面),因此加载它们可能需要一些时间.您可以在下面找到每一个:

So, within this InitialViewController, you make the authentication check in viewDidAppear(). If the user is logged in, we perform a segue to the home view controller. If not, we animate the user onboarding elements into place. The gifs demonstrating what I mean are pretty large (dimension-wise and data-wise), so they may take some time to load. You can find each one below:

用户先前已登录.

User previously logged in.

用户先前未登录.

User not previously logged in.

这是我在InitialViewController中执行检查的方式:

This is how I perform the check within InitialViewController:

@IBOutlet var loginButton: UIButton!
@IBOutlet var signupButton: UIButton!
@IBOutlet var stackView: UIStackView!
@IBOutlet var stackViewVerticalCenterConstraint: NSLayoutConstraint!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    //When the view appears, we want to check to see if the user is logged in.
    //Remember, the interface builder is set up so that this view controller **initially** looks identical to the launch screen
    //This gives the effect that the authentication check is occurring before the app actually finishes launching
    checkLoginStatus()
}

func checkLoginStatus() {
    //If the user was previously logged in, go ahead and segue to the main app without making them login again

    guard
        let email = UserDefaults.standard.string(forKey: "email"),
        let password = UserDefaults.standard.string(forKey: "password")
    else {
        // User has no defaults, animate onboarding elements into place
        presentElements()
        return
    }

    let authentificator = Authentificator()
    authentificator.login(with: email, password) { result, _ in
        if result {
            //User is authenticated, perform the segue to the first view controller you want the user to see when they are logged in
            self.performSegue(withIdentifier: "SkipLogin", sender: self)
        }
    }
}

func presentElements() {

    //This is the part where the illusion comes into play
    //The storyboard elements, like the login and signup buttons were always here, they were just hidden
    //Now, we are going to animate the onboarding UI elements into place
    //If this function is never called, then the user will be unaware that the launchscreen was even replaced with this view controller that handles the authentication check for us

    //Make buttons visible, but...
    loginButton.isHidden = false
    signupButton.isHidden = false

    //...set their alpha to 0
    loginButton.alpha = 0
    signupButton.alpha = 0

    //Calculate distance to slide up
    //(stackView is the stack view that holds our elements like loginButton and signupButton. It is invisible, but it contains these buttons.)
    //(stackViewVerticalCenterConstraint is the NSLayoutConstraint that determines our stackView's vertical position)
    self.stackViewVerticalCenterConstraint.constant = (view.frame.height / 2) + (stackView.frame.height / 2)

    //After half a second, we are going to animate the UI elements into place
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        UIView.animate(withDuration: 0.75) {
            self.loginButton.alpha = 1
            self.signupButton.alpha = 1

            //Create correct vertical position for stackView
            self.stackViewVerticalCenterConstraint.constant = (self.view.frame.height - self.navigationController!.navigationBar.frame.size.height - self.signupButton.frame.maxY - (self.stackView.frame.size.height / 2)) / 3
            self.view.layoutIfNeeded()
        }
    }   
}

这篇关于在应用启动之前执行完成处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆