представления объединяются, а не отображаются отдельно - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть два 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, все новое.

UPDATE

Я использовал следующий блок как в viewDidAppear (если в localstorage есть электронная почта, вместо экрана входа в систему отображается представление шагов расширения), так и в функции входа в систему, когда вход выполнен успешно, но он не переходит к этому ExtensionStepsView

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

Вариант использования: show login at initial, но если пользователь вошел в систему, отобразить другое представление, но теперь проблема заключается в том, что представление объединено

enter image description here

1 Ответ

0 голосов
/ 06 сентября 2018

Вы получили сообщение об ошибке "Тип Bool не имеет подписных элементов", потому что loadNibNamed (_: owner: topLevelObjects:) метод Bundle возвращает Bool struct that не имеет подписок участников, поэтому вы не можете писать как

true[0]

Как правильно использовать этот метод, смотрите ссылку и пример оттуда:

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 ) и его XIBS.
  3. Сразу после входа пользователя транзит из LoginViewController в ExtensionStepsViewController

В качестве примера, но вместо ParentViewController вы должны использовать вашу реализацию SafariExtensionViewController, как я объяснил выше в первом шаге.

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")
        }
    }
}

Здесь - быстрая игровая площадка с этим примером.

UPD:

Вы можете создать экземпляр NSViewController несколькими способами:

  1. Использование NSStoryboard , позволяющее загрузить представление NSViewController из файла .storyboard:
let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil)
let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))
  1. Используйте соответствующий инициализатор NSViewController, чтобы загрузить его из файла .xib:
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
  1. Используйте инициализатор по умолчанию, но вы должны загрузить представление напрямую, переопределив метод loadView () , если имя файла xib отличается от имени класса контроллера представления:
let steps = ExtensionStepsViewController()
// Also you have to override loadView() method of ExtensionStepsViewController.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...