2017-09-26 34 views
1

我在我的应用程序的日记功能中使用PassithLock swift源代码。我正在使用密码来允许用户锁定日记,以便人们无法打开应用程序并阅读其条目。不能在现有tableview控制器上显示.xib视图控制器

我的项目中的.xib文件是应该显示的实际密码锁定屏幕。附加的PasscodeLockPresenter.swift文件是负责通过现有窗口呈现视图控制器并呈现锁定屏幕的文件。 Touch ID也为锁定屏幕启用。当我进入应用程序的屏幕上应该显示锁定屏幕时,触摸ID的提示出现,但没有锁定屏幕视图控制器。我该如何解决这个问题?这只是一个赛格错误吗?

PasscodeLockPresenter.swift

import UIKit 

open class PasscodeLockPresenter { 

    fileprivate var mainWindow: UIWindow? 

    fileprivate lazy var passcodeLockWindow: UIWindow = { 

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

     window.windowLevel = 0 
     window.makeKeyAndVisible() 

     return window 
    }() 

    fileprivate let passcodeConfiguration: PasscodeLockConfigurationType 
    open var isPasscodePresented = false 
    open let passcodeLockVC: PasscodeLockViewController 

    public init(mainWindow window: UIWindow?, configuration: PasscodeLockConfigurationType, viewController: PasscodeLockViewController) { 

     mainWindow = window 
     mainWindow?.windowLevel = 1 
     passcodeConfiguration = configuration 

     passcodeLockVC = viewController 
    } 

    public convenience init(mainWindow window: UIWindow?, configuration: PasscodeLockConfigurationType) { 

     let passcodeLockVC = PasscodeLockViewController(state: .enterPasscode, configuration: configuration) 

     self.init(mainWindow: window, configuration: configuration, viewController: passcodeLockVC) 
    } 

    open func presentPasscodeLock() { 

     guard passcodeConfiguration.repository.hasPasscode else { return } 
     guard !isPasscodePresented else { return } 

     isPasscodePresented = true 

     passcodeLockWindow.windowLevel = 2 
     passcodeLockWindow.isHidden = false 

     mainWindow?.windowLevel = 1 
     mainWindow?.endEditing(true) 

     let passcodeLockVC = PasscodeLockViewController(state: .enterPasscode, configuration: passcodeConfiguration) 
     let userDismissCompletionCallback = passcodeLockVC.dismissCompletionCallback 

     passcodeLockVC.dismissCompletionCallback = { [weak self] in 

      userDismissCompletionCallback?() 

      self?.dismissPasscodeLock() 
     } 

     passcodeLockWindow.rootViewController = passcodeLockVC 
    } 

    open func dismissPasscodeLock(animated: Bool = true) { 

     isPasscodePresented = false 
     mainWindow?.windowLevel = 1 
     mainWindow?.makeKeyAndVisible() 

     if animated { 

      animatePasscodeLockDismissal() 

     } else { 

      passcodeLockWindow.windowLevel = 0 
      passcodeLockWindow.rootViewController = nil 
     } 
    } 

    internal func animatePasscodeLockDismissal() { 

     UIView.animate(
      withDuration: 0.5, 
      delay: 0, 
      usingSpringWithDamping: 1, 
      initialSpringVelocity: 0, 
      options: UIViewAnimationOptions(), 
      animations: { [weak self] in 

       self?.passcodeLockWindow.alpha = 0 
      }, 
      completion: { [weak self] _ in 

       self?.passcodeLockWindow.windowLevel = 0 
       self?.passcodeLockWindow.rootViewController = nil 
       self?.passcodeLockWindow.alpha = 1 
      } 
     ) 
    } 
} 

PasscodeLockViewController.swift

import UIKit 

open class PasscodeLockViewController: UIViewController, PasscodeLockTypeDelegate { 

    public enum LockState { 
     case enterPasscode 
     case setPasscode 
     case changePasscode 
     case removePasscode 

     func getState() -> PasscodeLockStateType { 

      switch self { 
      case .enterPasscode: return EnterPasscodeState() 
      case .setPasscode: return SetPasscodeState() 
      case .changePasscode: return ChangePasscodeState() 
      case .removePasscode: return EnterPasscodeState(allowCancellation: true) 
      } 
     } 
    } 

    @IBOutlet open weak var titleLabel: UILabel? 
    @IBOutlet open weak var descriptionLabel: UILabel? 
    @IBOutlet open var placeholders: [PasscodeSignPlaceholderView] = [PasscodeSignPlaceholderView]() 
    @IBOutlet open weak var cancelButton: UIButton? 
    @IBOutlet open weak var deleteSignButton: UIButton? 
    @IBOutlet open weak var touchIDButton: UIButton? 
    @IBOutlet open weak var placeholdersX: NSLayoutConstraint? 

    open var successCallback: ((_ lock: PasscodeLockType) -> Void)? 
    open var dismissCompletionCallback: (()->Void)? 
    open var animateOnDismiss: Bool 
    open var notificationCenter: NotificationCenter? 

    internal let passcodeConfiguration: PasscodeLockConfigurationType 
    internal let passcodeLock: PasscodeLockType 
    internal var isPlaceholdersAnimationCompleted = true 

    fileprivate var shouldTryToAuthenticateWithBiometrics = true 

    // MARK: - Initializers 

    public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) { 

     self.animateOnDismiss = animateOnDismiss 

     passcodeConfiguration = configuration 
     passcodeLock = PasscodeLock(state: state, configuration: configuration) 

     let nibName = "PasscodeLockView" 
     let bundle: Bundle = bundleForResource(nibName, ofType: "nib") 

     super.init(nibName: nibName, bundle: bundle) 

     passcodeLock.delegate = self 
     notificationCenter = NotificationCenter.default 
    } 

    public convenience init(state: LockState, configuration: PasscodeLockConfigurationType, animateOnDismiss: Bool = true) { 

     self.init(state: state.getState(), configuration: configuration, animateOnDismiss: animateOnDismiss) 
    } 

    public required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    deinit { 

     clearEvents() 
    } 

    // MARK: - View 

    open override func viewDidLoad() { 
     super.viewDidLoad() 

     updatePasscodeView() 
     deleteSignButton?.isEnabled = false 

     setupEvents() 
    } 

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

     if shouldTryToAuthenticateWithBiometrics { 

      authenticateWithBiometrics() 
     } 
    } 

    internal func updatePasscodeView() { 

     titleLabel?.text = passcodeLock.state.title 
     descriptionLabel?.text = passcodeLock.state.description 
     cancelButton?.isHidden = !passcodeLock.state.isCancellableAction 
     touchIDButton?.isHidden = !passcodeLock.isTouchIDAllowed 
    } 

    // MARK: - Events 

    fileprivate func setupEvents() { 

     notificationCenter?.addObserver(self, selector: #selector(PasscodeLockViewController.appWillEnterForegroundHandler(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) 
     notificationCenter?.addObserver(self, selector: #selector(PasscodeLockViewController.appDidEnterBackgroundHandler(_:)), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) 
    } 

    fileprivate func clearEvents() { 

     notificationCenter?.removeObserver(self, name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil) 
     notificationCenter?.removeObserver(self, name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) 
    } 

    open func appWillEnterForegroundHandler(_ notification: Notification) { 

     authenticateWithBiometrics() 
    } 

    open func appDidEnterBackgroundHandler(_ notification: Notification) { 

     shouldTryToAuthenticateWithBiometrics = false 
    } 

    // MARK: - Actions 

    @IBAction func passcodeSignButtonTap(_ sender: PasscodeSignButton) { 

     guard isPlaceholdersAnimationCompleted else { return } 

     passcodeLock.addSign(sender.passcodeSign) 
    } 

    @IBAction func cancelButtonTap(_ sender: UIButton) { 

     dismissPasscodeLock(passcodeLock) 
    } 

    @IBAction func deleteSignButtonTap(_ sender: UIButton) { 

     passcodeLock.removeSign() 
    } 

    @IBAction func touchIDButtonTap(_ sender: UIButton) { 

     passcodeLock.authenticateWithBiometrics() 
    } 

    fileprivate func authenticateWithBiometrics() { 

     if passcodeConfiguration.shouldRequestTouchIDImmediately && passcodeLock.isTouchIDAllowed { 

      passcodeLock.authenticateWithBiometrics() 
     } 
    } 

    internal func dismissPasscodeLock(_ lock: PasscodeLockType, completionHandler: (() -> Void)? = nil) { 

     // if presented as modal 
     if presentingViewController?.presentedViewController == self { 

      dismiss(animated: animateOnDismiss, completion: { [weak self] _ in 

       self?.dismissCompletionCallback?() 

       completionHandler?() 
      }) 

      return 

     // if pushed in a navigation controller 
     } else if navigationController != nil { 

      navigationController?.popViewController(animated: animateOnDismiss) 
     } 

     dismissCompletionCallback?() 

     completionHandler?() 
    } 

    // MARK: - Animations 

    internal func animateWrongPassword() { 

     deleteSignButton?.isEnabled = false 
     isPlaceholdersAnimationCompleted = false 

     animatePlaceholders(placeholders, toState: .error) 

     placeholdersX?.constant = -40 
     view.layoutIfNeeded() 

     UIView.animate(
      withDuration: 0.5, 
      delay: 0, 
      usingSpringWithDamping: 0.2, 
      initialSpringVelocity: 0, 
      options: [], 
      animations: { 

       self.placeholdersX?.constant = 0 
       self.view.layoutIfNeeded() 
      }, 
      completion: { completed in 

       self.isPlaceholdersAnimationCompleted = true 
       self.animatePlaceholders(self.placeholders, toState: .inactive) 
     }) 
    } 

    internal func animatePlaceholders(_ placeholders: [PasscodeSignPlaceholderView], toState state: PasscodeSignPlaceholderView.State) { 

     for placeholder in placeholders { 

      placeholder.animateState(state) 
     } 
    } 

    fileprivate func animatePlacehodlerAtIndex(_ index: Int, toState state: PasscodeSignPlaceholderView.State) { 

     guard index < placeholders.count && index >= 0 else { return } 

     placeholders[index].animateState(state) 
    } 

    // MARK: - PasscodeLockDelegate 

    open func passcodeLockDidSucceed(_ lock: PasscodeLockType) { 

     deleteSignButton?.isEnabled = true 
     animatePlaceholders(placeholders, toState: .inactive) 
     dismissPasscodeLock(lock, completionHandler: { [weak self] _ in 
      self?.successCallback?(lock) 
     }) 
    } 

    open func passcodeLockDidFail(_ lock: PasscodeLockType) { 

     animateWrongPassword() 
    } 

    open func passcodeLockDidChangeState(_ lock: PasscodeLockType) { 

     updatePasscodeView() 
     animatePlaceholders(placeholders, toState: .inactive) 
     deleteSignButton?.isEnabled = false 
    } 

    open func passcodeLock(_ lock: PasscodeLockType, addedSignAtIndex index: Int) { 

     animatePlacehodlerAtIndex(index, toState: .active) 
     deleteSignButton?.isEnabled = true 
    } 

    open func passcodeLock(_ lock: PasscodeLockType, removedSignAtIndex index: Int) { 

     animatePlacehodlerAtIndex(index, toState: .inactive) 

     if index == 0 { 

      deleteSignButton?.isEnabled = false 
     } 
    } 
} 

EnterPasscodeState.swift

import Foundation 

public let PasscodeLockIncorrectPasscodeNotification = "passcode.lock.incorrect.passcode.notification" 

struct EnterPasscodeState: PasscodeLockStateType { 

    let title: String 
    let description: String 
    let isCancellableAction: Bool 
    var isTouchIDAllowed = true 

    fileprivate var inccorectPasscodeAttempts = 0 
    fileprivate var isNotificationSent = false 

    init(allowCancellation: Bool = false) { 

     isCancellableAction = allowCancellation 
     title = localizedStringFor("PasscodeLockEnterTitle", comment: "Enter passcode title") 
     description = localizedStringFor("PasscodeLockEnterDescription", comment: "Enter passcode description") 
    } 

    mutating func acceptPasscode(_ passcode: [String], fromLock lock: PasscodeLockType) { 

     guard let currentPasscode = lock.repository.passcode else { 
      return 
     } 

     if passcode == currentPasscode { 

      lock.delegate?.passcodeLockDidSucceed(lock) 

     } else { 

      inccorectPasscodeAttempts += 1 

      if inccorectPasscodeAttempts >= lock.configuration.maximumInccorectPasscodeAttempts { 

       postNotification() 
      } 

      lock.delegate?.passcodeLockDidFail(lock) 
     } 
    } 

    fileprivate mutating func postNotification() { 

     guard !isNotificationSent else { return } 

     let center = NotificationCenter.default 

     center.post(name: Notification.Name(rawValue: PasscodeLockIncorrectPasscodeNotification), object: nil) 

     isNotificationSent = true 
    } 
} 

PasscodeLock.swift

import Foundation 
import LocalAuthentication 

open class PasscodeLock: PasscodeLockType { 

    open weak var delegate: PasscodeLockTypeDelegate? 
    open let configuration: PasscodeLockConfigurationType 

    open var repository: PasscodeRepositoryType { 
     return configuration.repository 
    } 

    open var state: PasscodeLockStateType { 
     return lockState 
    } 

    open var isTouchIDAllowed: Bool { 
     return isTouchIDEnabled() && configuration.isTouchIDAllowed && lockState.isTouchIDAllowed 
    } 

    fileprivate var lockState: PasscodeLockStateType 
    fileprivate lazy var passcode = [String]() 

    public init(state: PasscodeLockStateType, configuration: PasscodeLockConfigurationType) { 

     precondition(configuration.passcodeLength > 0, "Passcode length sould be greather than zero.") 

     self.lockState = state 
     self.configuration = configuration 
    } 

    open func addSign(_ sign: String) { 

     passcode.append(sign) 
     delegate?.passcodeLock(self, addedSignAtIndex: passcode.count - 1) 

     if passcode.count >= configuration.passcodeLength { 

      lockState.acceptPasscode(passcode, fromLock: self) 
      passcode.removeAll(keepingCapacity: true) 
     } 
    } 

    open func removeSign() { 

     guard passcode.count > 0 else { return } 

     passcode.removeLast() 
     delegate?.passcodeLock(self, removedSignAtIndex: passcode.count) 
    } 

    open func changeStateTo(_ state: PasscodeLockStateType) { 

     lockState = state 
     delegate?.passcodeLockDidChangeState(self) 
    } 

    open func authenticateWithBiometrics() { 

     guard isTouchIDAllowed else { return } 

     let context = LAContext() 
     let reason = NSLocalizedString("PasscodeLockTouchIDReason", comment: "TouchID authentication reason") 

     context.localizedFallbackTitle = localizedStringFor("PasscodeLockTouchIDButton", comment: "TouchID authentication fallback button") 

     context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { 
      success, error in 

      self.handleTouchIDResult(success) 
     } 
    } 

    fileprivate func handleTouchIDResult(_ success: Bool) { 

     DispatchQueue.main.async { 

      if success { 

       self.delegate?.passcodeLockDidSucceed(self) 
      } 
     } 
    } 

    fileprivate func isTouchIDEnabled() -> Bool { 

     let context = LAContext() 

     return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) 
    } 
} 

太谢谢你了!

而且,我使用我的tableviewcontroller这段代码试图递交LOCKSCREEN的的.xib

var passcodeLockPresenter: PasscodeLockPresenter = { 

      let configuration = PasscodeLockConfiguration() 
      let presenter = PasscodeLockPresenter(mainWindow: self.view.window, configuration: configuration) 

      return presenter 
     }() 
     passcodeLockPresenter.presentPasscodeLock() 

回答

0

您是否尝试过委派回你的VC或使用完毕块,你可以VC处理演示?利用当前(viewController:animated :) API是最佳实践。

+0

对不起,麻烦,但我是一个快速编程新手,我将如何去执行到我的代码?提前谢谢你 –

相关问题