Подтвердить что ты не робот

Двойной знак вопроса, как это работает?

Я изучаю Свифт и, как часть процесса, пытаюсь выяснить, что именно происходит здесь. У меня есть пользовательский segue, где я хочу, чтобы мой диспетчер modal view отклонил переход. Что раньше было в objective-c как:

UIViewController *sourceViewController = self.sourceViewController;
[sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];

self является экземпляром UIStoryboardSegue. Я перевел этот фрагмент в Swift как:

self.sourceViewController.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

получить эту ошибку от компилятора:

'UIViewController? не имеет члена, названного 'DismissViewControllerAnimated'

Теперь по документации метод presentingViewController выглядит следующим образом:

var presentingViewController: UIViewController? { get }

Из того, что я понял в документации по языку Swift, ? должен развернуть значение, если оно есть. В этом случае контроллер вида. Необъяснимый факт: если я ставил двойной вопросительный знак, он компилируется и работает:

self.sourceViewController.presentingViewController??.dismissViewControllerAnimated(true, completion: nil)

Может ли кто-нибудь сказать мне, что мне не хватает? Что это должно сделать?

4b9b3361

Ответ 1

Дополнительный ? требуется sourceViewController вернуть AnyObject вместо UIViewController. Это недостаток в преобразовании API из Objective-C (в котором такое свойство возвращает довольно бессмысленный id). Это все еще продолжающийся процесс, который начался с iOS 8 beta 5, и, по-видимому, эти API еще не исправлены.

Если вы предоставите соответствующий бросок, он будет работать как ожидалось

(self.sourceViewController as UIViewController).presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

Теперь, зачем нам понадобиться дополнительный ? при работе с AnyObject?

AnyObject может представлять любой тип объекта, в основном, как id в Objective-C. Поэтому во время компиляции вы можете вызывать на нем любой существующий метод, например sourceViewController.

Когда вы это сделаете, он вызывает неявное понижение от AnyObject до UIViewController и в соответствии с официальным руководством :

Как и во всех downcasts в Swift, отбрасывание из AnyObject в более конкретный тип объекта не гарантируется и, следовательно, возвращает необязательное значение

Итак, когда вы делаете

self.sourceViewController.presentingViewController??

он неявно переводит на что-то вроде

 let source: UIViewController? = self.sourceViewController as? UIViewController
 let presenting: UIViewController? = source?.presentingViewController

и что вам нужно два ?: один для разрешения downcast и один для presentingViewController.

Наконец, всегда в соответствии с документацией:

Конечно, если вы уверены в типе объекта (и знаете, что это не ноль), вы можете принудительно вызвать вызов с помощью оператора as.

который является именно моим предложенным решением выше.