2015-10-05 11 views
10

Il mio scenario è simile al seguente: Ho una classe che ha una funzione al suo interno e questa funzione effettua una richiesta POST a un server con NSURLSession. In un'altra funzione che non è in quella classe, chiamo quella funzione con l'attività in essa, che funziona in modo asincrono, penso. Sto riscontrando il seguente problema: quando scarico la risposta JSON dal server e la scrivo in una variabile e la restituisco, la variabile che ho scritto è ancora nullo dal momento che non ha atteso il completamento del thread/task e restituisce il valore iniziale che è nullo.Attendi il completamento dell'attività di download in NSURLSession

Quindi la mia domanda è come posso aspettare che quell'attività termini e poi continuare l'intero programma.

Questa è la mia classe con la funzione di richiesta:

class DownloadTask { 
var json:NSDictionary! 
var cookie:String! 
var responseString : NSString = "" 

func forData(completion: (NSString) ->()) { 

    var theJSONData:NSData! 
    do { 
     theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions()) 
    } catch _ { 
     print("error") 
    } 

    let request = NSMutableURLRequest(URL: url) 
    request.HTTPMethod = "POST" 
    request.setValue("application/json", forHTTPHeaderField: "Content-Type") 
    if cookie != nil { 
     request.setValue(cookie, forHTTPHeaderField: "Cookie") 
    } 
    request.HTTPBody = theJSONData 

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { 
     data, response, error in 

     if error != nil { 
      print("error") 
      return 
     } else { 
      completion(NSString(data: data!, encoding: NSUTF8StringEncoding)!) 
     } 
    } 
    task.resume() 
} 

}

E questo è il mio codice chiamante:

let task = DownloadTask() 
task.forData { jsonString in 
    do { 
     if let json: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding)!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary { 
      if json["error"] != nil { 
       authenticated = false 
      } else { 
       let result = json["result"] as! NSDictionary 
       user.personId = result["personId"] as! NSNumber 
       user.sessionId = result["sessionId"] as! NSString 
       print("test0") 
       authenticated = true 
      } 
     } 
    } 
    catch _ { 
     print("error") 
    } 
} 
print("test1") 

L'output è:

test1 
test0 

E non posso asso ss le variabili user.sessionId dopo quell'attività.

+0

Hai finito per capirlo? – Mihado

risposta

11

Come ho detto prima nei commenti del post principale, il download NSURLSession.sharedSession().dataTaskWithRequest(request) viene eseguito in modo sincrono sul thread principale, il che significa che scarica i dati in modo sincrono per la visualizzazione. Quindi, in breve, print("test0") verrà eseguito al termine del thread inviato (ovvero i dati vengono scaricati). Per risolvere questo problema ho dovuto usare i semafori (ho anche combinato il primo codice e il secondo codice dalla domanda iniziale):

private func downloadData(completion: (String) ->()) { 
    let semaphore = dispatch_semaphore_create(0); 
    let request = NSMutableURLRequest(URL: url) 

    var theJSONData = NSData() 
    do { 
     theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions()) 
    } catch { 
     completion(String()) 
    } 

    request.HTTPMethod = "POST" 
    request.setValue("application/json", forHTTPHeaderField: "Content-Type") 
    request.HTTPBody = theJSONData 

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { 
     data, response, error in 
     data == nil ? completion(String()) : completion(String(data: data!, encoding: NSUTF8StringEncoding)!) 
     dispatch_semaphore_signal(semaphore); 
    } 
    task.resume() 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
} 

Questo non può essere il più efficiente, né la soluzione più elegante, ma nel mio caso ho davvero ho dovuto aspettare che il download finisse altrimenti non dovrebbe fare nulla.

+0

Nell'ultimo Swift: 'lasciare semaforo = DispatchSemaphore (valore: 0)' ' poi nel URLSession.shared.dataTask' ' semaphore.signal() '' _ = semaphore.wait (timeout: DispatchTime.distantFuture) ' –

Problemi correlati