2015-06-08 7 views
15

Sto provando a testare una piccola app a riga di comando di prova prima di integrarla in un'applicazione più grande. Quello che sto cercando di fare è scaricare alcuni dati usando NSURLSession usando this example. Tuttavia, sembra che se utilizzo gli esempi forniti in una semplice app da riga di comando di OS X, l'app si chiude prima che i dati vengano recuperati.Utilizzo di NSURLSession da un programma a riga di comando Swift

Come posso scaricare i dati da un'app di riga di comando autonoma utilizzando NSURLSession? Quello che ho letto sta usando NSRunLoop ma non ho ancora trovato un chiaro esempio in Swift, quindi se NSRunLoop è in realtà la strada da percorrere allora qualsiasi esempio sarebbe apprezzato.

Qualsiasi altra strategia per scaricare dati da un URL per un'app di riga di comando Swift è anch'essa benvenuta (ciclo while infinito?).

+2

Prova ad aggiungere 'NSRunLoop. mainRunLoop(). run() 'alla fine del tuo file ... – nielsbot

+0

Grazie, funziona. Quindi, per confermare, questo funziona fino a quando il programma non viene terminato esternamente? Puoi aggiungerlo come risposta e qualsiasi informazione aggiuntiva sarebbe apprezzata. Come a) come uscire programmaticamente b) e un po 'di informazioni di base sul perché è meglio di un ciclo infinito. –

+0

sì - sarà solo per sempre. – nielsbot

risposta

20

È possibile utilizzare un semaforo per bloccare il thread corrente e attendere il completamento della sessione dell'URL.

Creare il semaforo, avviare la sessione dell'URL, quindi attendere il semaforo. Dal richiamo del completamento della sessione URL, segnala il semaforo.

È possibile utilizzare un flag globale (dichiarare una variabile booleana volatile) e eseguire il polling da un ciclo while, ma ciò è meno ottimale. Per prima cosa, stai bruciando inutilmente i cicli della CPU.

Ecco un rapido esempio ho fatto usando un parco giochi:

import Foundation 

var sema = DispatchSemaphore(value: 0) 

class Delegate : NSObject, URLSessionDataDelegate 
{ 
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) 
    { 
     print("got data \(String(data: data, encoding: .utf8) ?? "<empty>")"); 
     sema.signal() 
    } 
} 

let config = URLSessionConfiguration.default 
let session = URLSession(configuration: config, delegate: Delegate(), delegateQueue: nil) 

guard let url = URL(string:"http://apple.com") else { fatalError("Could not create URL object") } 

session.dataTask(with: url).resume()  

sema.wait() 
+0

Questa è davvero una buona soluzione.Ho davvero bisogno di un framework intorno a questa idea per tenere traccia di tutti i semafori che creeresti se necessario. – Tatsh

+0

Probabilmente una volta che Swift ottiene il supporto nativo per le funzionalità di tipo "asincrono", non sarà più necessario. – nielsbot

+0

Se si desidera una soluzione di alto livello, consultare 'NSOperationQueue' e' NSBlockOperation' – nielsbot

2

Se è solo a scopo di test, è possibile evitare l'utilizzo del semaforo se codificare "tempo di esecuzione" della riga di comando di app come questo :

SWIFT 3

//put at the end of your main file 
RunLoop.main.run(until: Date(timeIntervalSinceNow: 15)) //will run your app for 15 seconds only 

Questo è molto rapido e sporco modo per "abilitare" le applicazioni della linea di comando per attendere il completamento di altri thread. Inoltre, l'app uscirà normalmente al termine del timeout, senza la necessità di annullare o annullare esplicitamente il processo dell'app.

NOTA:

  1. è possibile modificare periodo 'timeout' se le attività di rete richiedono più tempo per completare.
  2. Questa 'soluzione' è sicuramente decisione poveri se si vuole di più serio meccanismo di attesa (aka. Non USO QUESTO IN PRODUZIONE)
+0

può 'dormire (15)' fare lo stesso trucco? (rispondi da http://stackoverflow.com/a/40870288/1135503) –

+0

@KentLiau: supponi la funzione C sleep()? In tal caso, devi importare il modulo Darwin, ma fai attenzione al sistema operativo su cui stai eseguendo il codice. – Vexy

1

Prova questo

let sema = DispatchSemaphore(value: 0) 

let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg")!; 

let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
    print("after image is downloaded"); 
    sema.signal(); // signals the process to continue 
}; 

task.resume(); 
sema.wait(); // sets the process to wait 
Problemi correlati