Пользовательский Segue в Swift

@objc(SEPushNoAnimationSegue)
class SEPushNoAnimationSegue: UIStoryboardSegue {
    override func perform () {
      self.sourceViewController.navigationController.pushViewController(self.destinationViewController, animated:false)
    }
}

В приведенном выше коде у меня есть 2 вопроса: 1). он имеет ошибку компиляции: 'UINavigationController! не имеет члена с именем 'pushViewController'

Но в этом классе он имеет метод pushViewController.

2). Я должен добавить аннотацию: @objc (SEPushNoAnimationSegue), в противном случае в раскадровке он распознает только случайное сгенерированное имя, например, _tcxxxxSEPushNoAnimationSegue.

почему эти два вопроса происходят здесь?

Ответы

Ответ 1

Проблема №1

UIStoryboardSegue имеет раздражающий недостаток: его свойства sourceViewController и destinationViewController набираются как AnyObject! (этот случай даже в Objective-C (тип идентификатора)), а не как UIViewController, как и должно быть.

Тот же недостаток создает хаос в вашем совершенном и простом коде. Здесь, как переписать его, чтобы исправить ошибки компиляции:

@objc(SEPushNoAnimationSegue)
class SEPushNoAnimationSegue: UIStoryboardSegue {
    override func perform () {
        let src = self.sourceViewController as UIViewController
        let dst = self.destinationViewController as UIViewController
        src.navigationController.pushViewController(dst, animated:false)
    }
}

ПРИМЕЧАНИЕ. Apple исправила эту вещь в iOS 9. sourceViewController и destinationViewController теперь корректно объявлены как UIViewController.

Проблема № 2

Компилятор Swift сохраняет свои символы, используя свое собственное название mangling, а good ol Objective-C не распознает его в Xcode. Использование явного @obj() решает проблему.

Ответ 2

Это отлично работает для меня

@objc(SEPushNoAnimationSegue) class SEPushNoAnimationSegue: UIStoryboardSegue {

override func perform() {
    let sourceViewController = self.sourceViewController as UIViewController
    let destinationViewController = self.destinationViewController as UIViewController

    sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil)
}

}

Ответ 3

Даже лучше:

import UIKit

class CustomSegue: UIStoryboardSegue {
    override func perform() {
        self.sourceViewController.presentViewController(self.destinationViewController as UIViewController, animated: false, completion: nil)
    }
}

Ответ 4

Swift 3.0:

import UIKit

class CustomNoAnimationSegue: UIStoryboardSegue {

    override func perform() {
        if let navigation = source.navigationController {
            navigation.pushViewController(destination, animated: false)
        }
    }
}