2015-08-24 8 views
11

Sto scrivendo del codice in Swift per imparare la lingua. Qui è la mia classe di base:Swift tuple to Optional assignment

import Foundation 
class BaseCommand:NSOperation 
{ 
    var status:Int? = nil 
    var message:String? = nil 

    func buildRequest() -> NSData? 
    { 
     return nil 
    } 

    func parseResponse(data:NSData?) -> (Status:Int, Error:String) 
    { 
     return (200, "Success") 
    } 

    override func main() { 
     let requestBody = self.buildRequest() 

     println("Sending body \(requestBody)") 
     // do network op 
     var networkResultBody = "test" 

     var resultBody:NSData = networkResultBody.dataUsingEncoding(NSUTF8StringEncoding)! 
     (self.status, self.message) = self.parseResponse(resultBody) 
    } 
} 

Il problema è l'ultima riga:

(self.status, self.message) = self.parseResponse(resultBody) 

Il compilatore dice che "non possono esprimere la conversione tuple (Stato: Int, Errore: String) per (Int ?, String?) "

Capisco che il problema è che self.status e self.message sono optionals, e parseResponse non restituisce Optionals (e io non lo voglio). Come faccio a dire che devo assegnare e convertire per ottenere i dati nelle variabili di istanza?

risposta

5

Un'altra risposta suggerito (prima che fosse cambiato) fare solo:

(self.status!, self.message!) = self.parseResponse(resultBody) 

Ho scoperto che è a rischio. Crollerà se self.status o self.message è nil al momento dell'assegnazione. Prova questo test in un parco giochi:

class Test { 
    var status: Int? 
    var error: String? 

    func parseResponse() -> (Status:Int, Error:String) 
    { 
     return (200, "Success") 
    } 

    func testIt() { 
     (self.status!, self.error!) = parseResponse() 
     print(self.status) 
     print(self.error) 
    } 
} 

let mytest = Test() 
mytest.testIt() 

Ecco un altro modo potrebbe essere fatto:

let (stat, err) = self.parseResponse(resultBody) 
(self.status, self.error) = (Optional(stat), Optional(err)) 

o, come ha scoperto @AndriyGordiychuk, funziona senza Optional:

let (stat, err) = self.parseResponse(resultBody) 
(self.status, self.error) = (stat, err) 

È curioso che funzioni, ma non assegnare il risultato della funzione.


Nota il seguente esperimento:

var i: Int? 
var s: String? 

// This works 
(i, s) = (3, "hello") 

// This fails with error: cannot express tuple conversion '(Int, String)' to '(Int?, String?) 
let t = (3, "hello") 
(i, s) = t 

Sembra che quando l'assegnazione è una tupla letterale assegnato ad una tupla, Swift prende una scorciatoia e non prima costruire il tupla. Invece, assegna solo i singoli elementi.

Quindi questo:

(i, s) = (3, "hello") 

è equivalente a:

i = 3 
s = "hello" 

che funziona perché è possibile assegnare un Int a un Int? variabile e un String a una variabile String?. L'assegnazione della tupla non riesce perché i tipi devono corrispondere.

+0

puoi scomporre la tupla e ricostruirla (i, s) = (t.0, t.1) –

3

quello che dovete fare questo (senza optional necessari):

let returnValue = self.parseResponse(resultBody) 
(self.status,self.message) = (returnValue.Status,returnValue.Error) 
+0

Il tuo primo metodo andrà in crash se 'self.status' o' self.message' sono 'nil' al momento. – vacawama

+0

L'ho provato. E non si schianta. Perché dovrebbe? Si arresterebbe in modo anomalo se stavate scartandoli e assegnandoli a qualcosa che si aspetta valori non nulli. Lo srotolamento esplicito di nil non causa un crash da solo;) –

+0

Vedere la mia risposta. Il test del mio parco giochi si blocca sia in Xcode 6.4 che in 7.0 beta 5 se 'self.status' o' self.message' sono 'nil'. – vacawama