2014-07-17 13 views
13

Sto cercando di scrivere una funzione che eseguirà una richiesta GET asincrona e restituirà la risposta (come qualsiasi tipo di dati, ma qui è come NSData).Come ottenere dati incompletiHandler in Swift in NSURConnection

Questa domanda si basa su: How to use NSURLConnection completionHandler with swift

func getAsynchData() -> NSData { 
    var dataOutput : NSData 
    let url:NSURL = NSURL(string:"some url") 
    let request:NSURLRequest = NSURLRequest(URL:url) 
    let queue:NSOperationQueue = NSOperationQueue() 

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in 
      /* this next line gives the below error */ 
      dataOutput = data 
    }) 
    return dataOutput 
} 

ma ottengo un errore:

error: variable 'dataOutput' captured by a closure before being initialized 

ho cercato di restituire il valore dalla completionHandler, ma richiede un ritorno vuoto, che stranamente mi ricorda la mia speranza di risolvere questo problema senza aiuto ...: D

Ho visto: How to use completionHandler Closure with return in Swift? ma questo in realtà non risponde alla mia domanda. Il mio obiettivo qui è quello di ottenere i dati dalla mia richiesta asincrona dal blocco, per utilizzarli altrove nel mio codice. Dovrei fare tutto il lavoro con questa richiesta in questo blocco e non ottenere i dati?

Grazie!

EDIT

ok quindi ho un'opzione che credo potrebbe funzionare, ma non mi sembra giusto per me. Qualcuno può dirmi se questo è il modo migliore per raggiungere il mio obiettivo?

func doThingsWithData(data: NSData) -> String { 
    /* code to extract string from NSData */ 
    return somestring 
} 
func getAsynchData() { 
    let url:NSURL = NSURL(string:"some url") 
    let request:NSURLRequest = NSURLRequest(URL:url) 
    let queue:NSOperationQueue = NSOperationQueue() 

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in 
      /* this next line gives the below error */ 
      doThingsWithData(data) 
    }) 
} 

EDIT 2 -> risposta per annullare

Grazie, Undo. La tua risposta ha senso per me. Ecco di più del puzzle. Ho una classe che è il mio gestore API. Voglio essere in grado di creare un'istanza di quella classe e chiamare una funzione su di essa per ottenere i dati dall'API. Preferirei ottenere tutti i dati con una sola chiamata API, piuttosto che effettuare chiamate separate ogni volta per ogni valore che ho bisogno di uscire, in quanto una singola chiamata API contiene tutti i dati di cui ho bisogno, ma potrebbe essere un'altra risposta. Ecco il codice:

class GetInfoFromAPI { 

    func getSpecificValue(index : String) -> String { 
     /* I assume I need to send the values from this function, yea? but how do I get them here? */ 
    } 

    func doThingsWithData(data: NSData) -> String { 
     /* code to extract string from NSData */ 
     var error: NSError? 
     let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as NSDictionary 

     specificValue1 : String = jsonDict.valueForKey("value1") as String 
     specificValue2 : String = jsonDict.valueForKey("value2") as String 
     specificValue3 : String = jsonDict.valueForKey("value3") as String 

     /* I want to get these ^^^ values into the ViewController below */ 
    } 

    func getAsynchData() { 
     let url:NSURL = NSURL(string:"some url") 
     let request:NSURLRequest = NSURLRequest(URL:url) 
     let queue:NSOperationQueue = NSOperationQueue() 

     NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in 
      /* this next line gives the below error */ 
      doThingsWithData(data) 
     }) 
    } 
} 


class ViewController: UIViewController { 

    @IBOutlet var labelVariable1: UILabel 
    @IBOutlet var labelVariable2: UILabel 
    @IBOutlet var labelVariable3: UILabel 

    let apiInstance = GetInfoFromAPI() 

    @IBAction func buttonTapped(sender : AnyObject) { 
     labelVariable1 = apiInstance.getSpecificValue(1) 
     labelVariable2 = apiInstance.getSpecificValue(2) 
     labelVariable3 = apiInstance.getSpecificValue(3) 
    } 

} 

Grazie per aver dedicato del tempo a rispondere alle mie domande. Sono nuovo di swift, e lo stack overflow è immensamente utile!

+2

Cosa dire di 'var dataOutput: NSData!'? – cahn

+0

quando uso 'var dataOutput: NSData!', Viene visualizzato il seguente errore: 'errore fatale: inaspettatamente trovato nil durante lo srotolamento di un valore Optional'. Credo che questo sia probabilmente perché è una richiesta asincrona e non ha immediatamente un valore da restituire. questo mi porta a credere che la mia seconda modifica sia probabilmente il modo migliore di andare a – cosmikwolf

+0

ma buono a sapersi! semplicemente scaricando implicitamente una variabile consente di accedervi all'interno di funzioni annidate? ho fatto facepalmed quando ho visto la tua risposta: D – cosmikwolf

risposta

6

Lasciatemi provare a spiegare questo - è un fraintendimento del threading, con il quale io stesso ho dovuto lottare all'inizio. Cercherò di semplificare un po 'le cose. Quando si esegue questo codice:

NSLog("Log 1") 

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in 
     NSLog("Log in Completion Block") 
}) 

NSLog("Log after request") 

Stai andando a ottenere l'output che assomiglia a questo:

Log 1 
Log after request 
Log in completion block 

lasciatemi fare un grafico, specie di una linea temporale:

    "Log 1" (before request is sent) 
             | 
             | 
          Request sent over Internet 
             | 
            / \ 
        "Log after request" | 
       This is logged *before* | 
      the other one, because this | 
      one doesn't have to wait for | 
       the network to respond. | 
             | 
The method finishes and returns a value. | 
------------------------------------------------------------------------------ 
             | The network finally responds, 
             | and the completion block is run. 
             | 

             "Log in completion block" 

La linea verticale è dove il metodo finisce e ritorna. In tutti i casi, il metodo avrà già restituito un valore al chiamante prima dell'esecuzione del blocco di completamento. Non puoi pensare a questo in modo lineare.

Am I supposed to do all of the work with this request in this block and not get the data out?

Sì, in sostanza. Posso aiutare di più se mi mostri il codice che chiama getAsynchData() in primo luogo.

+0

Grazie Annulla, è stato molto utile. Ho aggiunto più codice al corpo principale sopra che dà un'immagine più grande del problema. – cosmikwolf

+1

Grazie! Sono un po 'occupato al momento, cercherò di tornare a questo in un giorno o due. Nel frattempo, penso che sia necessario esaminare il concetto di delegati e protocolli. Questo dovrebbe darti un buon inizio. – Undo

+0

grazie, lo farò! Attendo la tua risposta. – cosmikwolf