IOS - Как программировать с помощью swift

185

Я создаю приложение, которое использует Facebook SDK для аутентификации пользователей. Я пытаюсь объединить логику facebook в отдельном классе. Вот код (вырезанный для простоты):

import Foundation

class FBManager {
    class func fbSessionStateChane(fbSession:FBSession!, fbSessionState:FBSessionState, error:NSError?){
        //... handling all session states
        FBRequestConnection.startForMeWithCompletionHandler { (conn: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in

            println("Logged in user: \n\(result)");

            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
            let loggedInView: UserViewController = storyboard.instantiateViewControllerWithIdentifier("loggedInView") as UserViewController

            loggedInView.result = result;

            //todo: segue to the next view???
        }
    }
}

Я использую метод класса выше, чтобы проверить изменения состояния сеанса, и он работает нормально.

Q: Как только у меня есть данные пользователя, как я могу перейти к следующему представлению в этом пользовательском классе?

РЕДАКТИРОВАТЬ: просто чтобы быть ясно, у меня есть переход с идентификатором на раскадровке, и я пытаюсь найти способ выполнить переход из класса, который не является контроллером представления

Шломи Шварц
источник
2
Как performSegue:?
ИМЕЕТ
Да, но кода нет в viewController, как мне этого добиться?
Шломи Шварц
Что ж, в этом случае вы должны делегировать эту работу (переход) от объекта, с которым вы выполняете работу, контроллеру представления (через блок завершения или метод делегата).
ИМЕЕТ
получить исключение макета не ноль
Крис Хейс

Ответы:

340

Если ваш сценарий существует в раскадровке с идентификатором перехода между двумя вашими представлениями, вы можете просто вызвать его программно, используя:

performSegue(withIdentifier: "mySegueID", sender: nil)

Для более старых версий:

performSegueWithIdentifier("mySegueID", sender: nil)

Вы также можете сделать:

presentViewController(nextViewController, animated: true, completion: nil)

Или, если вы находитесь в навигационном контроллере:

self.navigationController?.pushViewController(nextViewController, animated: true)
Жером
источник
7
Спасибо за ответ, как я могу вызвать executeSegueWithIdentifier из пользовательского класса, который не является представлением?
Шломи Шварц
2
Если я использую ваш второй метод. Как передать данные на следующий просмотр?
Iamprem
2
Вы должны использовать func prepareForSegue (segue: UIStoryboardSegue, sender: AnyObject?) И установить свойства.
Ллойд Сарджент
1
Обратите внимание, что при вызове executeSequeWithIdentifer () будет вызываться реализация prepareForSeque () в вызывающем контроллере, и вы можете выполнять передачу различных данных туда - фактически, параметр sender, полученный в prepareForSeque (), - это просто то, что передается параметру sender в executeSequeWithIdentifier ()
Тимбо
1
Что делать, если в раскадровке нет перехода? Например, если вы хотите создать переход к самому ViewController?
страшно
20

Вы можете использовать NSNotification

Добавьте метод post в свой пользовательский класс:

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

Добавьте наблюдателя в свой ViewController:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOFReceivedNotication:", name:"NotificationIdentifier", object: nil)

Добавьте функцию в свой ViewController:

func methodOFReceivedNotication(notification: NSNotification){
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
}
Родриго Отеро
источник
1
Пожалуйста, не злоупотребляйте такими уведомлениями. Используйте делегата и сделайте связь между контроллером представления и вашим классом явной. Почти невозможно наблюдать поток управления уведомлением, потому что может быть несколько подписчиков, и экземпляры могут подписываться / отписываться по желанию.
Uliwitness
17

Если ваш сценарий существует в раскадровке с идентификатором перехода между двумя вашими представлениями, вы можете просто вызвать его программно, используя

self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)

Если вы находитесь в навигационном контроллере

let viewController = YourViewController(nibName: "YourViewController", bundle: nil)        
self.navigationController?.pushViewController(viewController, animated: true)

Я рекомендую вас для второго подхода с использованием навигационного контроллера.

Маниш Махаджан
источник
self.performSegue (withIdentifier: "yourIdentifierInStoryboard", отправитель: самость)
Rajneesh071
14

Вы можете использовать Segue, как это:

self.performSegueWithIdentifier("push", sender: self)
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if segue.identifier == "push" {

    }
}
Рудра
источник
Спасибо за ответ, однако executeSegueWithIdentifier является методом viewController, и мой код выполняется во внешнем классе
Shlomi Schwartz
13

Swift 3 - также работает со SpriteKit

Вы можете использовать NSNotification .

Пример:

1.) Создайте переход в раскадровке и назовите идентификатор «segue»

2.) Создайте функцию в ViewController, от которого вы переходите.

func goToDifferentView() {

    self.performSegue(withIdentifier: "segue", sender: self)

}

3.) В ViewDidLoad () вашего ViewController вы переходите от создания наблюдателя.

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: "segue" as NSNotification.Name, object: nil)

Обновление - в прошлый раз, когда я использовал это, я должен был изменить .addObserverвызов на следующий код, чтобы заглушить ошибки.

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)

4.) В ViewController или Scene, к которому вы обращаетесь, добавьте метод Post везде, где вы хотите, чтобы переход запускался.

NotificationCenter.default.post(name: "segue" as NSNotification.Name, object: nil)

Обновление - в прошлый раз, когда я использовал это, я должен был изменить .postвызов на следующий код, чтобы заглушить ошибки.

NotificationCenter.default.post(NSNotification(name: NSNotification.Name(rawValue: "segue"), object: nil) as Notification)
Тимми Соренсен
источник
Свифт 3:NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)
Михаил Самойлов
3

То, что вы хотите сделать, действительно важно для модульного тестирования. По сути, вам нужно создать небольшую локальную функцию в контроллере вида. Назовите функцию как угодно, просто включите performSegueWithIndentifier.

func localFunc() {
    println("we asked you to do it")
    performSegueWithIdentifier("doIt", sender: self)
}

Затем измените свой служебный класс, FBManagerчтобы он включал инициализатор, который принимает аргумент функции, и переменную для хранения функции ViewController, которая выполняет поиск.

public class UtilClass {

    var yourFunction : () -> ()

    init (someFunction: () -> ()) {
        self.yourFunction = someFunction
        println("initialized UtilClass")
    }

    public convenience init() {
        func dummyLog () -> () {
            println("no action passed")
        }
        self.init(dummyLog)
    }

    public func doThatThing() -> () {
        // the facebook login function
        println("now execute passed function")
        self.yourFunction()
        println("did that thing")
    }
}

(Удобный init позволяет использовать это в модульном тестировании без выполнения перехода.)

Наконец, где у вас есть // todo: segue to next view ???, поместите что-то вроде:

self.yourFunction()

В ваших модульных тестах вы можете просто вызвать его как:

let f = UtilClass()
f.doThatThing()

где doThatThing - ваш fbsessionstatechange и UtilClassэто FBManager.

Для вашего реального кода просто передайте localFunc(без скобок) класс FBManager.

Билл
источник
2

Это сработало для меня.

Прежде всего, дайте контроллеру представления в вашей раскадровке идентификатор Storyboard внутри инспектора идентификации. Затем используйте следующий пример кода (убедитесь, что класс, имя раскадровки и идентификатор раскадровки совпадают с теми, которые вы используете):

let viewController:
UIViewController = UIStoryboard(
    name: "Main", bundle: nil
).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
// .instantiatViewControllerWithIdentifier() returns AnyObject!
// this must be downcast to utilize it

self.presentViewController(viewController, animated: false, completion: nil)

Для получения более подробной информации смотрите http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html наилучшие пожелания

amdan
источник
1

Вы можете сделать это, используя performSegueWithIdentifierфункцию.

Скриншот

Синтаксис:

func performSegueWithIdentifier(identifier: String, sender: AnyObject?)

Пример :

 performSegueWithIdentifier("homeScreenVC", sender: nil)
Джайпракаш Дубей
источник
1

Другой вариант заключается в использовании модального перехода

ШАГ 1. Перейдите к раскадровке и присвойте View Controller идентификатор раскадровки . Вы можете найти место для изменения идентификатора раскадровки в Identity Inspector справа. Позволяет назвать ID раскадровкиModalViewController

ШАГ 2: Откройте контроллер представления «отправитель» (давайте назовем его ViewController) и добавьте в него этот код

public class ViewController {
  override func viewDidLoad() {
    showModalView()
  }

  func showModalView() {
    if let mvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as? ModalViewController {
      self.present(mvc, animated: true, completion: nil)
    }
  }
}

Обратите внимание, что View Controller, который мы хотим открыть, также называется ModalViewController

ШАГ 3: Чтобы закрыть ModalViewController, добавьте это к нему

public class ModalViewController {
   @IBAction func closeThisViewController(_ sender: Any?) {
      self.presentingViewController?.dismiss(animated: true, completion: nil)
   }
}
aphoe
источник
0

Это сработало для меня:

//Button method example
 @IBAction func LogOutPressed(_ sender: UIBarButtonItem) {

        do {
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)

        } catch let signOutError as NSError {
          print ("Error signing out: %@", signOutError)
        }


    }

источник