2015-06-15 10 views
11

Vorrei creare una funzione in Swift 2 che recuperi i dati da un URL e li restituisca come un oggetto JSON utilizzando NSURLSession. All'inizio, questo sembrava abbastanza semplice. Ho scritto quanto segue:In Swift 2, come posso restituire gli errori di analisi JSON al blocco di completamento?

func getJson(url:NSURL, completeWith: (AnyObject?,NSURLResponse?,NSError?)->Void) -> NSURLSessionTask? { 

    let session = NSURLSession.sharedSession() 
    let task = session.dataTaskWithURL(url) { 
     (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in 

     if error != nil { 
      completeWith(nil, response, error) 
     } 

     if let data = data { 

      do { 
       let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) 
      } catch let caught as NSError { 
       completeWith(nil, response, caught) 
      } 

      completeWith(object, response, nil) 

     } else { 
      completeWith(nil, response, error) 
     } 
    } 

    return task 
} 

Tuttavia, ciò non viene compilato perché il blocco di completamento non dichiara "getta". L'errore esatto è Cannot invoke 'dataTaskWithURL' with an argument list of type '(NSURL, (NSData?, NSURLResponse?, NSError?) throws -> Void)'. Anche se sto rilevando tutti gli errori nella mia istruzione do/catch, Swift vuole ancora propagare il NSError sulla catena. L'unico modo che posso vedere in giro è quello di utilizzare try!, in questo modo:

if let data = data { 

    let object:AnyObject? = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) 
    completeWith(object, response, nil) 

} else { 
    completeWith(nil, response, error) 
} 

Ora tutto compila bene, ma ho perso la NSError che è gettato da NSJSONSerialization.JSONObjectWithData.

È stato possibile catturare il NSError potenzialmente lanciato da NSJSONSerialization.JSONObjectWithData e propagarlo al blocco di completamento senza modificare la firma del blocco di completamento?

risposta

21

credo, il pescato non è esaustivo, quindi è necessario qualcosa di simile:

do 
{ 
    let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) 
    completeWith(object, response, nil) 
} catch let caught as NSError { 
    completeWith(nil, response, caught) 
} catch { 
    // Something else happened. 
    // Insert your domain, code, etc. when constructing the error. 
    let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil) 
    completeWith(nil, nil, error) 
} 
+1

Ciao. Quando provo questa risposta, ottengo uno strano errore usando Xcode 7 Beta 2. "'AnyObject' non è convertibile in 'AnyObject'". Non sono sicuro se questo è solo un problema di Xcode Beta, o no. Qualcun altro ha qualche problema con il blocco di codice sopra? – jguffey

2

di affrontare la questione da Jguffey. Ho visto lo stesso errore quando ho provato a chiamare la funzione come questa:

let taskResult = getJson(url!) { 
    (any: AnyObject,resp: NSURLResponse,error: NSError) in 

che dovrebbe essere simile a questo:

let taskResult = getJson(url!) { 
     (any: AnyObject?,resp: NSURLResponse?,error: NSError?) in 
+0

Grazie! Questo mi ha aiutato molto! – Lucas

1

NSJSONSerialization tiri ERRORE.TIPO e non NSError.

in modo che il codice corretto sarebbe

do { 
    let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) 
} catch let caught as ErrorType { 
    completeWith(nil, response, caught) 
} 

si cambia anche la tua firma metodo per ERRORE.TIPO.

Per questo motivo, la risposta accettata verrà sempre inserita nel blocco "Qualcos'altro accaduto" e non verrà mai segnalato l'errore generato da NSJSONSerialization.JSONObjectWithData.

Problemi correlati