2014-09-22 14 views
18

Sto imparando Swift e, come parte del processo, cercando di capire cosa sta succedendo esattamente qui. Ho un seguito personalizzato in cui voglio posizionare la mia transizione modale per la liquidazione del controller di visualizzazione. Quello che era in Objective-C come:Doppio punto interrogativo, come funziona?

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

self è un'istanza di UIStoryboardSegue. ho tradotto questo frammento a Swift come:

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

ottenere questo errore del compilatore: '? UIViewController'

non ha un membro denominato 'dismissViewControllerAnimated'

Ora, by documentation, il metodo presentingViewController assomiglia a questo:

var presentingViewController: UIViewController? { get } 

Da quello che ho capito dalla documentazione lingua Swift, ? dovrebbe scartare il valore, se ce ne sono In questo caso il controller della vista. Il fatto inspiegabile è: se ho messo un punto doppia domanda, compila e funziona:

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

Qualcuno può dirmi che cosa mi manca? Cosa dovrebbe fare?

+4

in attesa del motivo del -1. Capisco che potrebbe essere una domanda n00b (come ho detto: sto ** imparando **), ma penso di averlo formulato abbastanza chiaramente e non si tratta di un caso specifico né di qualcosa che potrei trovare documentato. –

+0

qual è la dichiarazione di 'sourceViewController'? –

+0

@GabrielePetronella Ho aggiornato la domanda. è una proprietà di un UIStoryboardSegue. –

risposta

18

Il fabbisogno supplementare ? è dovuto a sourceViewController restituisce un AnyObject anziché uno UIViewController. Questo è un difetto nella conversione dell'API da Objective-C (in cui tale proprietà restituisce un valore piuttosto insignificante id). È ancora un processo in corso iniziato con iOS 8 beta 5 e apparentemente queste API non sono state ancora risolte.

Se si fornisce un cast appropriato, funzionerà come previsto

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

Ora, perché abbiamo bisogno di un extra ? quando si tratta di AnyObject?

AnyObject può rappresentare qualsiasi tipo di oggetto, praticamente come id fa in Objective-C. Quindi, in fase di compilazione, è possibile richiamare qualsiasi metodo esistente su di esso, ad esempio sourceViewController.

Quando lo fa, si innesca un abbattuto implicita AnyObject-UIViewController e secondo la official guide:

Come per tutti i downcasts di Swift, colata da AnyObject a un tipo di oggetto più specifico non è garantito per successo e restituisce quindi un valore opzionale

quindi, quando si fa

self.sourceViewController.presentingViewController?? 

si traduce implicitamente a qualcosa come

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

ed è per questo avete bisogno di due ?: uno per risolvere gli afflitti e uno per il presentingViewController.

Infine, sempre secondo la documentazione:

Naturalmente, se si è certi del tipo di oggetto (e sapere che non è pari a zero), è possibile forzare l'invocazione con l'operatore as .

che è esattamente la mia soluzione proposta sopra.

+1

La spiegazione è abbastanza chiara, ma mi chiedo una cosa: il secondo '?' Allora sta facendo cosa? Il primo restituisce un'istanza scartata 'AnyObject', ma la seconda? Non è richiesto un tipo facoltativo per poter utilizzare quell'operatore? –

+0

@NicolaMiotto Penso di avere una spiegazione ragionevole, vedi il mio ultimo aggiornamento –

+0

@Gabriele molto carino, penso che puoi risparmiare un po 'di tempo girando questo codice, "let source: UIViewController? = Self.sourceViewController as? UIViewController lascia presentando: UIViewController ? = source? .presentingViewController ", a questo," se consenti presentation = self.sourceViewController as? UIViewController {} ". Comodo controllo degli optionals. –

Problemi correlati