2014-09-22 12 views
18

Uczę się Swift i, w ramach tego procesu, próbuję dowiedzieć się, co dokładnie się tutaj dzieje. Mam niestandardowe przejście, w którym chcę umieścić mój kontroler widoku modalnego, odrzucając przejście. Co było w celu C jako:Podwójny znak zapytania, jak to działa?

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

self jest wystąpienie UIStoryboardSegue. Przetłumaczyłem ten fragment w Swift jako:

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

otrzymuję ten błąd z kompilatora: 'UIViewController'

nie ma elementu o nazwie „dismissViewControllerAnimated”

Teraz by documentation metoda presentingViewController wygląda następująco:

var presentingViewController: UIViewController? { get } 

Z tego co zrozumiałem w dokumentacji języka Swift, ? należy rozpakować wartość, Jeśli w ogóle. W tym przypadku kontroler widoku. Niewyjaśnione Faktem jest, jeśli mogę umieścić podwójny znak zapytania, kompiluje i działa:

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

Czy ktoś może mi powiedzieć, co mi brakuje? Co to powinno zrobić?

+4

oczekiwanie z powodu -1. Rozumiem, że może to być pytanie n00b (jak powiedziałem: ** uczę się **), ale myślę, że sformułowałem je dość wyraźnie i nie jest to konkretny przypadek ani nic, co mogłem znaleźć udokumentowane. –

+0

jaka jest deklaracja 'sourceViewController'? –

+0

@GabrielePetronella Zaktualizowałem pytanie. jest własnością UIStoryboardSegue. –

Odpowiedz

18

Wymagane dodatkowe ? jest wymagane sourceViewController zwrócenie AnyObject zamiast UIViewController. Jest to usterka konwersji API z Objective-C (w której taka właściwość zwraca dość bezsensowny id). To wciąż trwający proces, który rozpoczął się od wersji beta 8 systemu iOS 8 i najwyraźniej te interfejsy API nie zostały jeszcze naprawione.

Jeśli podasz odpowiednią obsadę, to będzie działać zgodnie z oczekiwaniami

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

Teraz, dlaczego potrzebujemy dodatkowy ? gdy ma do czynienia z AnyObject?

AnyObject może reprezentować dowolny typ obiektu, podobnie jak id ma w. Tak więc podczas kompilacji można wywołać dowolną istniejącą metodę, na przykład sourceViewController.

Kiedy to zrobisz, to wyzwala ukrytą spuszczone z AnyObject do UIViewController i zgodnie z official guide:

Jak wszystkie downcasts w Swift, odlewy z AnyObject do bardziej konkretnego typu obiektu nie jest gwarantowane sukces i dlatego zwraca opcjonalną wartość

więc kiedy zrobić

self.sourceViewController.presentingViewController?? 

to pośrednio przekłada się na coś takiego

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

i dlatego potrzebne są dwa ?: jeden dla rozstrzygnięcia przygnębiony i jeden dla presentingViewController.

Wreszcie, zawsze zgodnie z dokumentacją:

Oczywiście, jeśli jesteś pewien rodzaj obiektu (i wiem, że to nie jest zerowa), można wymusić inwokację z jako operator .

co jest dokładnie moim proponowanym rozwiązaniem powyżej.

+1

Wyjaśnienie jest całkiem jasne, ale zastanawiam się jedno: drugie "?" Robi co potem? Pierwszy z nich zwraca odwrócone wystąpienie "AnyObject", ale drugie? Czy opcjonalny typ nie jest wymagany do korzystania z tego operatora? –

+0

@NicolaMiotto Myślę, że mam sensowne wyjaśnienie, zobacz moją ostatnią aktualizację –

+0

Bardzo ładna @Gabriele, myślę, że możesz zaoszczędzić trochę czasu na przekręcaniu tego kodu, "niech źródło: UIViewController? = Self.sourceViewController jako? UIViewController niech przedstawia: UIViewController ? = source? .presentingViewController ", do tego", jeśli pozwala present = self.sourceViewController jako? UIViewController {} ". Wygodny wybór opcji. –