swift – 合并视图而不是单独显示它们

我有两个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没有下标成员我的文件结构看起来像这样.

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)

用例是在初始时显示登录,但如果用户登录则显示另一个视图,但问题是现在视图已合并

《swift – 合并视图而不是单独显示它们》

最佳答案 你得到错误“类型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.
点赞