这就是我所做的
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没有下标成员我的文件结构看起来像这样.
SafariExtensionViewController.xib (main one which is shown initially
with login screen)SafariExtensionViewController.swift
ExtensionStepsViewController.xib(this view should be shown when user
is logged in instead of login screen)ExtensionStepsViewController.swift
我正在使用xcode 10,swift 4,一切都是新的.
UPDATE
我在viewDidAppear中使用了以下块(如果localstorage中有电子邮件,然后显示扩展步骤视图而不是登录屏幕)和登录成功时内部登录功能,但它没有导航到该ExtensionStepsView
let controller = "ExtensionStepsViewController" let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil) self.view.addSubview(subview.view)
用例是在初始时显示登录,但如果用户登录则显示另一个视图,但问题是现在视图已合并
你得到错误“类型Bool没有下标成员”,因为 Bundle的 loadNibNamed(_:owner:topLevelObjects:)方法返回没有 subscript成员的 Bool结构所以你不能写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 }
视图已合并,因为您没有从superview中删除先前的视图,并将ExtensionStepsViewController中的视图添加到同一个superview.
您可以执行以下步骤来完成您的问题:
>使SafariExtensionViewController继承自SFSafariExtensionViewController,它将是两个子视图控制器(如LoginViewController和ExtensionStepsViewController)的容器(和父),并将用于在它们之间导航.
>单独制作LoginViewController和ExtensionStepsViewController(均继承自简单的NSViewController)及其xib.
>用户从LoginViewController到ExtensionStepsViewController登录transit之后
作为示例,但是您必须使用您的实现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:
>使用允许从.storyboard文件加载NSViewController视图的NSStoryboard:
let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil) let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))
>使用NSViewController的相应initialiser从.xib文件加载它的视图:
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
>使用默认初始化程序,但如果xib文件的名称与视图控制器类的名称不同,则必须通过重写loadView()方法直接加载视图:
let steps = ExtensionStepsViewController() // Also you have to override loadView() method of ExtensionStepsViewController.