视图被合并而不是分开显示

时间:2018-09-04 05:21:42

标签: swift xcode macos safari swift4

我有两个xib文件,一个显示登录视图,另一个显示成功登录后的操作步骤。我很难使它工作。我创建了macos项目而不是ios,并使用了safariservices,以便它可以用于safari扩展。

这就是我所做的

import SafariServices


class SafariExtensionViewController: SFSafariExtensionViewController {


    @IBOutlet weak var passwordMessage: NSTextField!
    @IBOutlet weak var emailMessage: NSTextField!
    @IBOutlet weak var message: NSTextField!
    @IBOutlet weak var email: NSTextField!
    @IBOutlet weak var password: NSSecureTextField!
    static let shared = SafariExtensionViewController()
    override func viewDidLoad() {
        self.preferredContentSize = NSSize(width: 300, height: 250)
        message.stringValue = ""
        emailMessage.stringValue = ""
        passwordMessage.stringValue = ""
    }
    override func viewDidAppear() {
        if let storedEmail = UserDefaults.standard.object(forKey: "email") as? String {
            if let stepView = Bundle.mainBundle.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: nil, topLevelObjects: nil)[0] {
                self.view.addSubview(stepView)
            }
        }
    }

    @IBAction func userLogin(_ sender: Any) {
        let providedEmailAddress = email.stringValue
        let providedPassword = password.stringValue
        let isEmailAddressValid = isValidEmailAddress(emailAddressString: providedEmailAddress)
        self.message.stringValue = ""
        emailMessage.stringValue = ""
        passwordMessage.stringValue = ""
        if isEmailAddressValid && providedPassword.count > 0 {
          /* login process is handled here and store the email in local storage /*
          /* TODO for now email is not stored in browser localstorage which has to be fixed */
         let controller = "ExtensionStepsViewController"
         let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
         self.view.addSubview(subview.view)
         }   
}
}

这样,我收到类似Type Bool has no subscript members的错误,我的文件结构看起来像这样。

  

SafariExtensionViewController.xib(最初显示的主要一个   登录屏幕)

     

SafariExtensionViewController.swift

     

ExtensionStepsViewController.xib(该视图应在用户   登录而不是登录屏幕

     

ExtensionStepsViewController.swift

我正在使用xcode 10,swift 4,所有新功能。

更新

我在viewDidAppear中使用了以下代码块(如果localstorage中有电子邮件,则显示扩展步骤视图而不是登录屏幕),并且在登录成功但未导航至该ExtensionStepsView时在登录功能内部使用

let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)

用例是最初显示登录名,但如果用户登录则显示另一个视图,但现在是视图合并了

enter image description here

1 个答案:

答案 0 :(得分:1)

您收到错误“ Type Bool没有下标成员”的错误信息,因为loadNibNamed(_:owner:topLevelObjects:)Bundle方法返回了没有Bool成员的subscript结构,因此您无法编写喜欢

true[0]

如何正确使用此方法,请参见link和示例:

var topLevelObjects : NSArray?
if Bundle.main.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: self, topLevelObjects: &topLevelObjects) {
     let  topLevelObjects!.first(where: { $0 is NSView }) as? NSView
}

视图被合并是因为您没有从超级视图中删除先前的视图,而是将视图从ExtensionStepsViewController添加到了同一超级视图中。

您可以按照以下步骤完成问题:

  1. 使SafariExtensionViewController继承自SFSafariExtensionViewController,它将成为两个子视图控制器(例如LoginViewController和ExtensionStepsViewController)的容器(和父容器),并将用于在两个子视图控制器之间进行导航。
  2. 分别制作LoginViewController和ExtensionStepsViewController(均继承自简单的NSViewController)及其xib。
  3. 用户从transit从LoginViewController登录到ExtensionStepsViewController之后

作为示例,您必须使用实现SafariExtensionViewController而不是ParentViewController,如我在第一步中上面所述。

public protocol LoginViewControllerDelegate: class {
    func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController)
}

public class LoginViewController: NSViewController {
    weak var delegate: LoginViewControllerDelegate?

    @IBAction func login(_ sender: Any) {
        // login logic
        let isLoginSuccessful = true
        if isLoginSuccessful {
            self.delegate?.loginViewControllerDidLoginSuccessful(self)
        }
    }
}

public class ExtensionStepsViewController: NSViewController {

}

public class ParentViewController: NSViewController, LoginViewControllerDelegate {
    weak var login: LoginViewController! // using of force unwrap is anti-pattern. consider other solutions
    weak var steps: ExtensionStepsViewController!

    public override func viewDidLoad() {
        let login = LoginViewController(nibName: NSNib.Name(rawValue: "LoginViewController"), bundle: nil)
        login.delegate = self
        // change login view frame if needed
        login.view.frame = self.view.frame
        self.view.addSubview(login.view)
        // instead of setting login view frame you can add appropriate layout constraints
        self.addChildViewController(login)
        self.login = login

        let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
        steps.view.frame = self.view.frame
        self.addChildViewController(steps)
        self.steps = steps
    }

    // MARK: - LoginViewControllerDelegate

    public func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController) {
        self.transition(from: self.login, to: self.steps, options: .slideLeft) {
            // completion handler logic
            print("transition is done successfully")
        }
    }
}

Here是这个示例的快速游乐场。

UPD:

您可以通过几种方式实例化NSViewController:

  1. 使用NSStoryboard允许从.storyboard文件加载NSViewController的视图:
let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil)
let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))
  1. 使用适当的initialiser的NSViewController从.xib文件中加载视图:
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
  1. 使用默认的初始化程序,但是如果xib文件的名称与视图控制器类的名称不同,则必须通过覆盖loadView()方法直接加载视图。
let steps = ExtensionStepsViewController()
// Also you have to override loadView() method of ExtensionStepsViewController.