封闭内的自我实例

时间:2017-10-16 14:36:43

标签: ios swift cocoa-touch

我在尝试动画并更改闭包内的ui元素的某些属性时遇到问题。当我尝试通过函数动画一些视图时,它执行函数但动画无法完成,但是当我在闭包外执行函数时,它工作正常。这是我的代码,我的问题出在AuthController底部的委托扩展中,名为facebookAuth的函数。我几乎挣扎了一天,我找不到错误。

我在动画中设置了一些打印语句,并且用于追踪目的,这些是执行的:

  

登录成功(这个是在委托函数中

     

幻灯片(这个是滑动功能)

     

不完整(这个是在动画关闭中)

AuthController

import UIKit
import AVFoundation
import FBSDKLoginKit
import FBSDKCoreKit
import Firebase

protocol AuthControllerDelegate {
    func login(withUser user: User)
    func facebookAuth()
    func signUp(withUser user: User)
    func facebookRegister(withEmail email: String, cellphone: String)
}

class AuthController: UIViewController {

    enum AuthView {
        case registerView
        case loginView
        case fbRegisterSecondStepCenter
    }

    private var player: AVPlayer!
    private var playerLayer: AVPlayerLayer!
    private var registerViewCenterConstraint: NSLayoutConstraint?
    private var loginViewCenterConstraint: NSLayoutConstraint?
    private var fbRegisterSecondStepCenterConstraint: NSLayoutConstraint?
    private var currentView: AuthView = .loginView
    private var facebookUserStore: User?

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }

    private let purpleBackground: UIView = {
        let pb = UIView()
        pb.backgroundColor = .darkBackground
        pb.alpha = 0.5
        return pb
    }()

    //MARK: AuthViews

    private lazy var loginView: LoginView = {
        let view = LoginView()
        view.delegate = self
        return view
    }()

    private lazy var registerView: RegisterView = {
        let view = RegisterView()
//        view.delegate = self
        view.alpha = 0
        return view
    }()

    private lazy var fbRegisterSecondStep: FBRegisterSecondStep = {
        let view = FBRegisterSecondStep()
        view.alpha = 0
        view.delegate = self
        return view
    }()

    private lazy var bottomBtn: UIButton = {
        let btn = UIButton()
        let attributedString = NSMutableAttributedString(string: "Not registered? Sign up.", attributes: [.foregroundColor: UIColor.lightText, .font: UIFont.init(name: Fonts.lightFont.rawValue, size: 16)!])
        btn.setAttributedTitle(attributedString, for: .normal)
        btn.contentHorizontalAlignment = .center
        btn.addTarget(self, action: #selector(handleChangeView), for: .touchUpInside)
        return btn
    }()

    let alertController: AlertController = {
        let ac = AlertController()
        return ac
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        print(UserDefaults.Account.bool(forKey: .isUserLoggedIn))
        setVideoBackground()
        setupViews()
        alertController.transitioningDelegate = alertController
        alertController.modalPresentationStyle = .custom
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.isNavigationBarHidden = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.isNavigationBarHidden = false
    }

    private func setupViews() {
        view.addSubview(purpleBackground)
        view.addSubview(loginView)
        view.addSubview(registerView)
        view.addSubview(fbRegisterSecondStep)
        view.addSubview(bottomBtn)

        _ = purpleBackground.anchor(top: view.topAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, left: view.leftAnchor)

        loginViewCenterConstraint = loginView.centerInView().first
        _ = loginView.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.6)

        registerViewCenterConstraint = registerView.centerInView().first
        registerViewCenterConstraint?.constant = 1000
        _ = registerView.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.8)

        fbRegisterSecondStepCenterConstraint = fbRegisterSecondStep.centerInView().first
        fbRegisterSecondStepCenterConstraint?.constant = 1000
        _ = fbRegisterSecondStep.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.5)

        _ = bottomBtn.anchor(top: nil, bottom: view.bottomAnchor, right: view.rightAnchor, left: view.leftAnchor, topConstant: 0, bottomConstant: 20, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 0)
    }

    private func setVideoBackground() {
        let videoPath = Bundle.main.url(forResource: "trim720", withExtension: "mp4")
        player = AVPlayer(url: videoPath!)
        playerLayer = AVPlayerLayer(player: player)
        playerLayer.videoGravity = .resizeAspectFill
        playerLayer.frame = view.frame
        player.actionAtItemEnd = .none
        player.play()

        view.layer.insertSublayer(playerLayer, at: 0)

        NotificationCenter.default.addObserver(self, selector: #selector(handleStop), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
    }

    private func slide(toView view: AuthView, completion: @escaping (Bool) -> Void = { _ in }) {
        guard let registerCenterConstraint = registerViewCenterConstraint, let loginCenterConstraint = loginViewCenterConstraint, let fbRegisterSecondConstraint = fbRegisterSecondStepCenterConstraint else {
            fatalError("Error unwrapping auth views constraints.")
        }
        switch view {
        case .loginView:
            loginCenterConstraint.constant = 0
            registerCenterConstraint.constant = 1000
            fbRegisterSecondConstraint.constant = 1000
            currentView = .loginView
        case .registerView:
            loginCenterConstraint.constant = 1000
            registerCenterConstraint.constant = 0
            fbRegisterSecondConstraint.constant = 1000
            currentView = .registerView
        case .fbRegisterSecondStepCenter:
            loginCenterConstraint.constant = 1000
            registerCenterConstraint.constant = 1000
            fbRegisterSecondConstraint.constant = 0
            currentView = .fbRegisterSecondStepCenter
            print("slideeeeeeeeeeee")
        }
        let isRegisterVisible = registerCenterConstraint.constant == 0
        let isLoginVisible = loginCenterConstraint.constant == 0
        let isFbRegisterVisible = fbRegisterSecondConstraint.constant == 0

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            self.registerView.alpha = isRegisterVisible ? 1 : 0
            self.loginView.alpha = isLoginVisible ? 1 : 0
            self.fbRegisterSecondStep.alpha = isFbRegisterVisible ? 1 : 0
            self.view.layoutIfNeeded()
            print("slide")
        }) { (state) in
            if state {
                print("completed")
            } else {
                print("not completed")
            }
            completion(state)
        }
    }

    fileprivate func pushHome() {
        navigationController?.isNavigationBarHidden = false
        navigationController?.setViewControllers([HomeController()], animated: true)
    }

    // MARK: Handlers

    @objc private func handleStop() {
        player.seek(to: kCMTimeZero)
    }

    @objc private func handleChangeView() {

        let isLoginVisible = currentView == .loginView
        let view: AuthView = isLoginVisible ? .registerView : .loginView
        slide(toView: view) { (completed) in
            let attributedString = self.bottomBtn.attributedTitle(for: .normal) as! NSMutableAttributedString
            let newTitle = isLoginVisible ? "Already an user? Sign In" : "Not registered? Sign up."
            attributedString.mutableString.setString(newTitle)
        }
    }
}

extension AuthController: Loginable, Registable, AuthControllerDelegate {

    func login(withUser user: User) {
        signIn(withUser: user) { (_) in
            self.pushHome()
        }
    }

    func facebookAuth(){
        let loginManager = FBSDKLoginManager()
        loginManager.logIn(withReadPermissions: ["email", "public_profile"], from: self) { (result, err) in
            if err == nil, !(result?.isCancelled)!, let token = result?.token.tokenString {
                print("Login successful")
                self.loginView.isHidden = true
                self.bottomBtn.isHidden = true
                self.slide(toView: .registerView)
            }
        }
    }

    func facebookRegister(withEmail email: String, cellphone: String) {
        guard let user = facebookUserStore else {
            fatalError("Error linking accounts")
        }
        register(withUser: user) { (completed) in
            if completed {
                self.linkAccount(withEmail: email, cellphone: cellphone, completion: { (completion) in
                    if completion {
                        self.pushHome()
                    }
                })
            }
        }
    }

    func signUp(withUser user: User) {
        register(withUser: user) { (_) in
            print("registrado")
            UserDefaults.Account.set(true, forKey: .isUserLoggedIn)
            self.pushHome()
        }
    }
}

当单击fbButton时,该函数通过此视图中的委托执行。

LoginView

//
//  LoginView.swift
//  TaxiApp
//
//  Created by Leonardo Dominguez on 10/2/17.
//  Copyright © 2017 Leonardo Dominguez. All rights reserved.
//

import UIKit

class LoginView: BaseView {

    var delegate: AuthControllerDelegate?

    private let emailField: TAField = {
        let pf = TAField(placeHolder: "E-mail", keyboardType: .emailAddress)
        return pf
    }()

    private let passwordField: TAField = {
        let pf = TAField(placeHolder: "Password")
        pf.isSecureTextEntry = true
        return pf
    }()

    private lazy var loginBtn: TAButton = {
        let btn = TAButton(title: "Login")
        btn.addTarget(self, action: #selector(handleLogin), for: .touchUpInside)
        return btn
    }()

    private let facebookBtn: TAButton = {
        let btn = TAButton()
        btn.backgroundColor = UIColor(hexString: "#3b5998")
        btn.setAttributedTitle(NSAttributedString(string: "Login with Facebook", attributes: [.foregroundColor: UIColor.lightText, .font: UIFont.init(name: Fonts.mediumFont.rawValue, size: 20)!]), for: .normal)
        return btn
    }()

    private let forgotPassword: UIButton = {
        let btn = UIButton()
        btn.setAttributedTitle(NSAttributedString(string: "Forgot password", attributes: [.foregroundColor: UIColor.placeholderText, .font: UIFont.init(name: Fonts.mediumFont.rawValue, size: 16)!]), for: .normal)
        btn.contentHorizontalAlignment = .right
        return btn
    }()

    private let orView: UIView = {
        let container = UIView()
        let lbl = UILabel()
        lbl.text = "or"
        lbl.textColor = .lightText
        lbl.font = UIFont(name: Fonts.mediumFont.rawValue, size: 20)
        let leftLine = UIView()
        let rightLine = UIView()
        leftLine.backgroundColor = .lightLine
        rightLine.backgroundColor = .lightLine
        container.addSubview(rightLine)
        container.addSubview(lbl)
        container.addSubview(leftLine)
        rightLine.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
        _ = rightLine.anchor(top: nil, bottom: nil, right: container.rightAnchor, left: lbl.rightAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 70, leftConstant: 3, widthConstant: 0, heightConstant: 1.0)
        _ = lbl.centerInView()
        leftLine.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
        _ = leftLine.anchor(top: nil, bottom: nil, right: lbl.leftAnchor, left: container.leftAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 3, leftConstant: 70, widthConstant: 0, heightConstant: 1.0)
        return container
    }()

    override func setupViews() {
        setupBtns()

        addSubview(emailField)
        addSubview(passwordField)
        addSubview(forgotPassword)
        addSubview(loginBtn)
        addSubview(orView)
        addSubview(facebookBtn)

        _ = emailField.anchor(top: topAnchor, bottom: nil, right: rightAnchor, left: leftAnchor, topConstant: 20, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: Theme.fieldHeight)

        _ = passwordField.anchorWithMultiplier(top: emailField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)

        _ = forgotPassword.anchor(top: passwordField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, topConstant: 5, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 0)

        _ = loginBtn.anchorWithMultiplier(top: passwordField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)

        _ = orView.anchor(top: loginBtn.bottomAnchor, bottom: nil, right: rightAnchor, left: leftAnchor, topConstant: Theme.topPadding / 2, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 10)

        _ = facebookBtn.anchorWithMultiplier(top: orView.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding / 2, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)

    }

    func setupBtns() {
        facebookBtn.addTarget(self, action: #selector(handleFacebookLogin), for: .touchUpInside)
    }

    @objc func handleFacebookLogin() {
        delegate?.facebookAuth()
    }

    @objc func handleLogin() {
        if let email = emailField.text, let password = passwordField.text {
            let user = User(email: email, password: password)
            delegate?.login(withUser: user)
        }
    }

}

更新

所以经过很多patinete尝试整个应用程序后,我只是注意到该错误属于RouterController,它是一个UINavigationController子类,其中嵌入了AuthController。当我更改windows rootviewcontroller以避免RouterController并直接转到AuthController时,一切都开始工作了......现在我的疑问是,为什么会发生这种情况?我试图搞清楚,所以我可以修复或将来的情况但我不知道为什么,这是我的代码:

RouterController

import UIKit

class RouterController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()
//        perform(#selector(redirect), with: nil, afterDelay: 0)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        redirect()
    }

    @objc func redirect() {
        if UserDefaults.Account.bool(forKey: .isUserLoggedIn) {
            viewControllers = [HomeController()]
        } else {
            setViewControllers([AuthController()], animated: false)
        }
    }
}

1 个答案:

答案 0 :(得分:0)

尝试在主线程的闭包中执行所有内容,如下所示:

func facebookAuth(){
    let loginManager = FBSDKLoginManager()
    loginManager.logIn(withReadPermissions: ["email", "public_profile"], from: self) {[weak self] (result, err) in
        if err == nil, !(result?.isCancelled)!, let token = result?.token.tokenString {
            print("Login successful")
            DispatchQueue.main.async {
                self?.loginView.isHidden = true
                self?.bottomBtn.isHidden = true
                self?.slide(toView: .registerView)
            }
        }
    }
}